diff --git a/src/kakarot/evm.cairo b/src/kakarot/evm.cairo index b302c3baa9..55e91c2932 100644 --- a/src/kakarot/evm.cairo +++ b/src/kakarot/evm.cairo @@ -349,37 +349,37 @@ namespace EVM { ret; call PushOperations.exec_push32; // 0x7f ret; - call DuplicationOperations.exec_dup1; // 0x80 + call DuplicationOperations.exec_dup; // 0x80 ret; - call DuplicationOperations.exec_dup2; // 0x81 + call DuplicationOperations.exec_dup; // 0x81 ret; - call DuplicationOperations.exec_dup3; // 0x82 + call DuplicationOperations.exec_dup; // 0x82 ret; - call DuplicationOperations.exec_dup4; // 0x83 + call DuplicationOperations.exec_dup; // 0x83 ret; - call DuplicationOperations.exec_dup5; // 0x84 + call DuplicationOperations.exec_dup; // 0x84 ret; - call DuplicationOperations.exec_dup6; // 0x85 + call DuplicationOperations.exec_dup; // 0x85 ret; - call DuplicationOperations.exec_dup7; // 0x86 + call DuplicationOperations.exec_dup; // 0x86 ret; - call DuplicationOperations.exec_dup8; // 0x87 + call DuplicationOperations.exec_dup; // 0x87 ret; - call DuplicationOperations.exec_dup9; // 0x88 + call DuplicationOperations.exec_dup; // 0x88 ret; - call DuplicationOperations.exec_dup10; // 0x89 + call DuplicationOperations.exec_dup; // 0x89 ret; - call DuplicationOperations.exec_dup11; // 0x8a + call DuplicationOperations.exec_dup; // 0x8a ret; - call DuplicationOperations.exec_dup12; // 0x8b + call DuplicationOperations.exec_dup; // 0x8b ret; - call DuplicationOperations.exec_dup13; // 0x8c + call DuplicationOperations.exec_dup; // 0x8c ret; - call DuplicationOperations.exec_dup14; // 0x8d + call DuplicationOperations.exec_dup; // 0x8d ret; - call DuplicationOperations.exec_dup15; // 0x8e + call DuplicationOperations.exec_dup; // 0x8e ret; - call DuplicationOperations.exec_dup16; // 0x8f + call DuplicationOperations.exec_dup; // 0x8f ret; call ExchangeOperations.exec_swap1; // 0x90 ret; diff --git a/src/kakarot/instructions/duplication_operations.cairo b/src/kakarot/instructions/duplication_operations.cairo index 818cd500b3..25a4b0f5ec 100644 --- a/src/kakarot/instructions/duplication_operations.cairo +++ b/src/kakarot/instructions/duplication_operations.cairo @@ -24,23 +24,38 @@ namespace DuplicationOperations { // @dev Duplicate the top i-th stack item to the top of the stack. // @param ctx The pointer to the execution context. // @return ExecutionContext Updated execution context. - func exec_dup_i{range_check_ptr}( - ctx: model.ExecutionContext*, i: felt - ) -> model.ExecutionContext* { + func exec_dup{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { alloc_locals; - let stack_underflow = is_le(ctx.stack.size, i - 1); - if (stack_underflow != 0) { - let (revert_reason_len, revert_reason) = Errors.stackUnderflow(); + let out_of_gas = is_le(ctx.call_context.gas_limit, ctx.gas_used + GAS_COST_DUP - 1); + if (out_of_gas != 0) { + let (revert_reason_len, revert_reason) = Errors.outOfGas(); let ctx = ExecutionContext.stop(ctx, revert_reason_len, revert_reason, TRUE); return ctx; } + if (ctx.stack.size == Constants.STACK_MAX_DEPTH) { let (revert_reason_len, revert_reason) = Errors.stackOverflow(); let ctx = ExecutionContext.stop(ctx, revert_reason_len, revert_reason, TRUE); return ctx; } + // See evm.cairo, pc is increased before entering the opcode + let opcode_number = [ctx.call_context.bytecode + ctx.program_counter - 1]; + let i = opcode_number - 0x7F; + + let stack_underflow = is_le(ctx.stack.size, i - 1); + if (stack_underflow != 0) { + let (revert_reason_len, revert_reason) = Errors.stackUnderflow(); + let ctx = ExecutionContext.stop(ctx, revert_reason_len, revert_reason, TRUE); + return ctx; + } + let (stack, element) = Stack.peek(ctx.stack, i - 1); let stack = Stack.push(stack, element); @@ -49,292 +64,4 @@ namespace DuplicationOperations { return ctx; } - - // @notice DUP1 operation - // @dev Duplicate the top stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup1{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=1); - return ctx; - } - - // @notice DUP2 operation - // @dev Duplicate the top 2nd stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup2{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=2); - return ctx; - } - - // @notice DUP3 operation - // @dev Duplicate the top 3rd stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup3{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=3); - return ctx; - } - - // @notice DUP4 operation - // @dev Duplicate the top 4th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup4{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=4); - return ctx; - } - - // @notice DUP5 operation - // @dev Duplicate the top 5th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup5{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=5); - return ctx; - } - - // @notice DUP6 operation - // @dev Duplicate the top 6th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup6{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=6); - return ctx; - } - - // @notice DUP7 operation - // @dev Duplicate the top 7th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup7{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=7); - return ctx; - } - - // @notice DUP8 operation - // @dev Duplicate the top 8th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup8{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=8); - return ctx; - } - - // @notice DUP9 operation - // @dev Duplicate the top 9th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup9{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=9); - return ctx; - } - - // @notice DUP10 operation - // @dev Duplicate the top 10th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup10{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=10); - return ctx; - } - - // @notice DUP11 operation - // @dev Duplicate the top 11th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup11{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=11); - return ctx; - } - - // @notice DUP12 operation - // @dev Duplicate the top 12th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup12{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=12); - return ctx; - } - - // @notice DUP13 operation - // @dev Duplicate the top 13th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup13{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=13); - return ctx; - } - - // @notice DUP14 operation - // @dev Duplicate the top 14th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup14{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=14); - return ctx; - } - - // @notice DUP15 operation - // @dev Duplicate the top 15th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup15{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=15); - return ctx; - } - - // @notice DUP16 operation - // @dev Duplicate the top 16th stack item to the top of the stack. - // @custom:since Frontier - // @custom:gas 3 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context. - // @return ExecutionContext Updated execution context. - func exec_dup16{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - let ctx = exec_dup_i(ctx=ctx, i=16); - return ctx; - } } diff --git a/tests/src/kakarot/instructions/test_duplication_operations.cairo b/tests/src/kakarot/instructions/test_duplication_operations.cairo index 1bb739ff7b..78d525612d 100644 --- a/tests/src/kakarot/instructions/test_duplication_operations.cairo +++ b/tests/src/kakarot/instructions/test_duplication_operations.cairo @@ -16,456 +16,19 @@ from kakarot.instructions.duplication_operations import DuplicationOperations from tests.utils.helpers import TestHelpers @external -func test__exec_dup1_should_duplicate_1st_item_to_top_of_stack{ +func test__exec_dup{ syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 1, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup1(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 2; - return (); -} - -@external -func test__exec_dup2_should_duplicate_2nd_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 2, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup2(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 3; - return (); -} - -@external -func test__exec_dup3_should_duplicate_3rd_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 3, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup3(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 4; - return (); -} - -@external -func test__exec_dup4_should_duplicate_4th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 4, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup4(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 5; - return (); -} - -@external -func test__exec_dup5_should_duplicate_5th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 5, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup5(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 6; - return (); -} - -@external -func test__exec_dup6_should_duplicate_6th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 6, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup6(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 7; - return (); -} - -@external -func test__exec_dup7_should_duplicate_7th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 7, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup7(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 8; - return (); -} - -@external -func test__exec_dup8_should_duplicate_8th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 8, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup8(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 9; - return (); -} - -@external -func test__exec_dup9_should_duplicate_9th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 9, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup9(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 10; - return (); -} - -@external -func test__exec_dup10_should_duplicate_10th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 10, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup10(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 11; - return (); -} - -@external -func test__exec_dup11_should_duplicate_11th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 11, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup11(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 12; - return (); -} - -@external -func test__exec_dup12_should_duplicate_12th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given +}(i: felt, stack_len: felt, stack: Uint256*) -> (result: Uint256) { + let stack_ = TestHelpers.init_stack_with_values(stack_len, stack); let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 12, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup12(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 13; - return (); -} - -@external -func test__exec_dup13_should_duplicate_13th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 13, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup13(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 14; - return (); -} - -@external -func test__exec_dup14_should_duplicate_14th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 14, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup14(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 15; - return (); -} - -@external -func test__exec_dup15_should_duplicate_15th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 15, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup15(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 16; - return (); -} - -@external -func test__exec_dup16_should_duplicate_16th_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, 16, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = DuplicationOperations.exec_dup16(ctx); - - // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = 17; - return (); -} - -@external -func test__exec_dup_i_should_duplicate_ith_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - alloc_locals; - // Test DUP1 -> DUP16 - _test__exec_dup_i_should_duplicate_ith_item_to_top_of_stack(16); - return (); -} - -@external -func _test__exec_dup_i_should_duplicate_ith_item_to_top_of_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}(i: felt) { - alloc_locals; - if (i == 0) { - return (); - } - - // Given - let (bytecode) = alloc(); - let stack = Stack.init(); - let start = 1; - let stack = TestHelpers.push_elements_in_range_to_stack(1, i, stack); - - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); + assert [bytecode] = i + 0x7f; + let ctx = TestHelpers.init_context_with_stack(1, bytecode, stack_); + let ctx = ExecutionContext.increment_program_counter(ctx, 1); // When - let result = DuplicationOperations.exec_dup_i(ctx, i); + let ctx = DuplicationOperations.exec_dup(ctx); // Then - assert result.gas_used = DuplicationOperations.GAS_COST_DUP; - let (stack, top) = Stack.peek(result.stack, 0); - assert top.low = start; - assert top.high = 0; - assert result.stack.size = i + 1; - return (); + let (stack_, top) = Stack.peek(ctx.stack, 0); + return ([top],); } diff --git a/tests/src/kakarot/instructions/test_duplication_operations.py b/tests/src/kakarot/instructions/test_duplication_operations.py index 4590c921b7..bb1d94dc7c 100644 --- a/tests/src/kakarot/instructions/test_duplication_operations.py +++ b/tests/src/kakarot/instructions/test_duplication_operations.py @@ -15,87 +15,10 @@ async def duplication_operations(starknet: Starknet): @pytest.mark.asyncio class TestDupOperations: - async def test__exec_dup1_should_duplicate_1st_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup1_should_duplicate_1st_item_to_top_of_stack().call() - - async def test__exec_dup2_should_duplicate_2nd_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup2_should_duplicate_2nd_item_to_top_of_stack().call() - - async def test__exec_dup3_should_duplicate_3rd_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup3_should_duplicate_3rd_item_to_top_of_stack().call() - - async def test__exec_dup4_should_duplicate_4th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup4_should_duplicate_4th_item_to_top_of_stack().call() - - async def test__exec_dup5_should_duplicate_5th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup5_should_duplicate_5th_item_to_top_of_stack().call() - - async def test__exec_dup6_should_duplicate_6th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup6_should_duplicate_6th_item_to_top_of_stack().call() - - async def test__exec_dup7_should_duplicate_7th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup7_should_duplicate_7th_item_to_top_of_stack().call() - - async def test__exec_dup8_should_duplicate_8th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup8_should_duplicate_8th_item_to_top_of_stack().call() - - async def test__exec_dup9_should_duplicate_9th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup9_should_duplicate_9th_item_to_top_of_stack().call() - - async def test__exec_dup10_should_duplicate_10th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup10_should_duplicate_10th_item_to_top_of_stack().call() - - async def test__exec_dup11_should_duplicate_11th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup11_should_duplicate_11th_item_to_top_of_stack().call() - - async def test__exec_dup12_should_duplicate_12th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup12_should_duplicate_12th_item_to_top_of_stack().call() - - async def test__exec_dup13_should_duplicate_13th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup13_should_duplicate_13th_item_to_top_of_stack().call() - - async def test__exec_dup14_should_duplicate_14th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup14_should_duplicate_14th_item_to_top_of_stack().call() - - async def test__exec_dup15_should_duplicate_15th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup15_should_duplicate_15th_item_to_top_of_stack().call() - - async def test__exec_dup16_should_duplicate_16th_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup16_should_duplicate_16th_item_to_top_of_stack().call() - - async def test__exec_dup_i_should_duplicate_ith_item_to_top_of_stack( - self, duplication_operations - ): - await duplication_operations.test__exec_dup_i_should_duplicate_ith_item_to_top_of_stack().call() + @pytest.mark.parametrize("i", range(1, 17)) + async def test__exec_dup(self, duplication_operations, i): + stack = [(v, 0) for v in range(16)] + (result,) = ( + await duplication_operations.test__exec_dup(i, stack).call() + ).result + assert result == stack[-i] diff --git a/tests/src/kakarot/instructions/test_stop_and_arithmetic_operations.cairo b/tests/src/kakarot/instructions/test_stop_and_arithmetic_operations.cairo index 430cdf768c..1a9fca9f65 100644 --- a/tests/src/kakarot/instructions/test_stop_and_arithmetic_operations.cairo +++ b/tests/src/kakarot/instructions/test_stop_and_arithmetic_operations.cairo @@ -42,11 +42,7 @@ func test__exec_arithmetic_operation{ alloc_locals; let (bytecode) = alloc(); assert [bytecode] = opcode; - let stack_ = Stack.init(); - - let stack_ = Stack.push_uint256(stack_, stack[2]); - let stack_ = Stack.push_uint256(stack_, stack[1]); - let stack_ = Stack.push_uint256(stack_, stack[0]); + let stack_ = TestHelpers.init_stack_with_values(stack_len, stack); let ctx = TestHelpers.init_context_with_stack(1, bytecode, stack_); let ctx = ExecutionContext.increment_program_counter(ctx, 1); diff --git a/tests/utils/helpers.cairo b/tests/utils/helpers.cairo index 06690d5c36..7e9ae02551 100644 --- a/tests/utils/helpers.cairo +++ b/tests/utils/helpers.cairo @@ -26,12 +26,7 @@ from kakarot.stack import Stack from utils.utils import Helpers namespace TestHelpers { - func init_context_at_address{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }( + func init_context_at_address( bytecode_len: felt, bytecode: felt*, starknet_contract_address: felt, @@ -62,32 +57,56 @@ namespace TestHelpers { return ctx; } - func init_context{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(bytecode_len: felt, bytecode: felt*) -> model.ExecutionContext* { + func init_context(bytecode_len: felt, bytecode: felt*) -> model.ExecutionContext* { return init_context_at_address(bytecode_len, bytecode, 0, 0); } - func init_context_with_stack{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(bytecode_len: felt, bytecode: felt*, stack: model.Stack*) -> model.ExecutionContext* { + func init_stack_with_values{range_check_ptr}(stack_len: felt, stack: Uint256*) -> model.Stack* { + let stack_ = Stack.init(); + + tempvar range_check_ptr = range_check_ptr; + tempvar stack_ = stack_; + tempvar stack_len = stack_len; + tempvar stack = stack; + + jmp cond; + + loop: + let range_check_ptr = [ap - 4]; + let stack_ = cast([ap - 3], model.Stack*); + let stack_len = [ap - 2]; + let stack = cast([ap - 1], Uint256*); + + let stack_ = Stack.push(stack_, stack); + + let range_check_ptr = [ap - 2]; + tempvar stack_len = stack_len - 1; + tempvar stack = stack + Uint256.SIZE; + + static_assert range_check_ptr == [ap - 4]; + static_assert stack_ == [ap - 3]; + static_assert stack_len == [ap - 2]; + static_assert stack == [ap - 1]; + + cond: + let stack_len = [ap - 2]; + jmp loop if stack_len != 0; + + let range_check_ptr = [ap - 4]; + let stack_ = cast([ap - 3], model.Stack*); + + return stack_; + } + + func init_context_with_stack( + bytecode_len: felt, bytecode: felt*, stack: model.Stack* + ) -> model.ExecutionContext* { let ctx: model.ExecutionContext* = init_context(bytecode_len, bytecode); let ctx = ExecutionContext.update_stack(ctx, stack); return ctx; } - func init_context_at_address_with_stack{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }( + func init_context_at_address_with_stack( starknet_contract_address: felt, evm_contract_address: felt, bytecode_len: felt, @@ -102,12 +121,7 @@ namespace TestHelpers { } // @notice Init an execution context where bytecode has "bytecode_count" entries of "value". - func init_context_with_bytecode{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(bytecode_count: felt, value: felt) -> model.ExecutionContext* { + func init_context_with_bytecode(bytecode_count: felt, value: felt) -> model.ExecutionContext* { alloc_locals; let (bytecode) = alloc(); @@ -116,12 +130,7 @@ namespace TestHelpers { return init_context(bytecode_count, bytecode); } - func init_context_with_return_data{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }( + func init_context_with_return_data( bytecode_len: felt, bytecode: felt*, return_data_len: felt, return_data: felt* ) -> model.ExecutionContext* { let ctx: model.ExecutionContext* = init_context(bytecode_len, bytecode); @@ -144,25 +153,6 @@ namespace TestHelpers { return (); } - // @notice Push n element-array starting from a specific value into the stack one at a time - // ex: If n = 3 and start = Uint256(0, 0), - // resulting stack elements will be [ Uint256(2, 0) ] - // [ Uint256(1, 0) ] - // [ Uint256(0, 0) ] - func push_elements_in_range_to_stack{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(start: felt, n: felt, stack: model.Stack*) -> model.Stack* { - if (n == 0) { - return stack; - } - - let updated_stack: model.Stack* = Stack.push_uint128(stack, start); - return push_elements_in_range_to_stack(start + 1, n - 1, updated_stack); - } - func assert_array_equal(array_0_len: felt, array_0: felt*, array_1_len: felt, array_1: felt*) { assert array_0_len = array_1_len; if (array_0_len == 0) {