From dc58b3be8ab6928bf35e7fc4472b8bf34938e043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Fri, 3 Nov 2023 13:46:43 +0100 Subject: [PATCH] Refacto BlockInfo and revert when OOG --- src/kakarot/constants.cairo | 2 - src/kakarot/evm.cairo | 18 +- .../instructions/block_information.cairo | 493 +++++++----------- src/kakarot/precompiles/precompiles.cairo | 2 +- src/kakarot/state.cairo | 9 +- .../instructions/test_block_information.cairo | 210 +------- .../instructions/test_block_information.py | 60 ++- 7 files changed, 281 insertions(+), 513 deletions(-) diff --git a/src/kakarot/constants.cairo b/src/kakarot/constants.cairo index 499d6a80c8..58f3d79c88 100644 --- a/src/kakarot/constants.cairo +++ b/src/kakarot/constants.cairo @@ -37,8 +37,6 @@ namespace Constants { // BLOCK // CHAIN_ID = KKRT (0x4b4b5254) in ASCII const CHAIN_ID = 1263227476; - // Coinbase address is the address of the sequencer - const MOCK_COINBASE_ADDRESS = 0x388ca486b82e20cc81965d056b4cdcaacdffe0cf08e20ed8ba10ea97a487004; // Hardcode block gas limit to 20M const BLOCK_GAS_LIMIT = 20000000; diff --git a/src/kakarot/evm.cairo b/src/kakarot/evm.cairo index 38989362e3..b302c3baa9 100644 --- a/src/kakarot/evm.cairo +++ b/src/kakarot/evm.cairo @@ -221,23 +221,23 @@ namespace EVM { ret; call EnvironmentalInformation.exec_extcodehash; // 0x3f ret; - call BlockInformation.exec_blockhash; // 0x40 + call BlockInformation.exec_block_information; // 0x40 ret; - call BlockInformation.exec_coinbase; // 0x41 + call BlockInformation.exec_block_information; // 0x41 ret; - call BlockInformation.exec_timestamp; // 0x42 + call BlockInformation.exec_block_information; // 0x42 ret; - call BlockInformation.exec_number; // 0x43 + call BlockInformation.exec_block_information; // 0x43 ret; - call BlockInformation.exec_difficulty; // 0x44 + call BlockInformation.exec_block_information; // 0x44 ret; - call BlockInformation.exec_gaslimit; // 0x45 + call BlockInformation.exec_block_information; // 0x45 ret; - call BlockInformation.exec_chainid; // 0x46 + call BlockInformation.exec_block_information; // 0x46 ret; - call BlockInformation.exec_selfbalance; // 0x47 + call BlockInformation.exec_block_information; // 0x47 ret; - call BlockInformation.exec_basefee; // 0x48 + call BlockInformation.exec_block_information; // 0x48 ret; call unknown_opcode; // 0x49 ret; diff --git a/src/kakarot/instructions/block_information.cairo b/src/kakarot/instructions/block_information.cairo index 9af6b947b3..f8f2e8878e 100644 --- a/src/kakarot/instructions/block_information.cairo +++ b/src/kakarot/instructions/block_information.cairo @@ -6,13 +6,13 @@ from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin from starkware.cairo.common.math_cmp import is_in_range, is_le -from starkware.cairo.common.math import split_felt from starkware.cairo.common.bool import FALSE, TRUE from starkware.starknet.common.syscalls import get_block_number, get_block_timestamp from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc // Internal dependencies -from kakarot.constants import Constants, native_token_address, blockhash_registry_address +from kakarot.constants import Constants, blockhash_registry_address from kakarot.execution_context import ExecutionContext from kakarot.interfaces.interfaces import IBlockhashRegistry from kakarot.model import model @@ -24,91 +24,15 @@ from utils.utils import Helpers // @title BlockInformation information opcodes. // @notice This file contains the functions to execute for block information opcodes. namespace BlockInformation { - // Define constants. - const GAS_COST_BLOCKHASH = 20; - const GAS_COST_COINBASE = 2; - const GAS_COST_TIMESTAMP = 2; - const GAS_COST_NUMBER = 2; - const GAS_COST_DIFFICULTY = 2; - const GAS_COST_GASLIMIT = 2; - const GAS_COST_CHAINID = 2; - const GAS_COST_SELFBALANCE = 5; - const GAS_COST_BASEFEE = 2; - - // @notice COINBASE operation. - // @dev Get the hash of one of the 256 most recent complete blocks. - // @dev 0 if the block number is not in the valid range. - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 20 - // @custom:stack_consumed_elements 1 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_blockhash{ + func exec_block_information{ syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*, }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { alloc_locals; - if (ctx.stack.size == 0) { - let (revert_reason_len, revert_reason) = Errors.stackUnderflow(); - let ctx = ExecutionContext.stop(ctx, revert_reason_len, revert_reason, TRUE); - return ctx; - } - - // Get the blockNumber - let (stack, block_number_uint256) = Stack.pop(ctx.stack); - let block_number = block_number_uint256.low; - - // Check if blockNumber is within bounds by checking with current block number - // Valid range is the last 256 blocks (not including the current one) - let (local current_block_number: felt) = get_block_number(); - let in_range = is_in_range(block_number, current_block_number - 256, current_block_number); - - // If not in range, return 0 - if (in_range == FALSE) { - tempvar blockhash = new Uint256(0, 0); - tempvar syscall_ptr = syscall_ptr; - tempvar pedersen_ptr = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar bitwise_ptr = bitwise_ptr; - } else { - let (blockhash_registry_address_: felt) = blockhash_registry_address.read(); - let (blockhash_: felt) = IBlockhashRegistry.get_blockhash( - contract_address=blockhash_registry_address_, block_number=[block_number_uint256] - ); - let blockhash = Helpers.to_uint256(blockhash_); - tempvar syscall_ptr = syscall_ptr; - tempvar pedersen_ptr = pedersen_ptr; - tempvar range_check_ptr = range_check_ptr; - tempvar bitwise_ptr = bitwise_ptr; - } - - let stack = Stack.push(stack, blockhash); - - let ctx = ExecutionContext.update_stack(ctx, stack); - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_BLOCKHASH); - return ctx; - } - - // @notice COINBASE operation. - // @dev Get the block's beneficiary address. - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_coinbase{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - // Get the coinbase address. + local range_check: felt; + local opcode: model.Opcode*; if (ctx.stack.size == Constants.STACK_MAX_DEPTH) { let (revert_reason_len, revert_reason) = Errors.stackOverflow(); @@ -116,246 +40,223 @@ namespace BlockInformation { return ctx; } - let coinbase_address = Helpers.to_uint256(val=Constants.MOCK_COINBASE_ADDRESS); - let stack: model.Stack* = Stack.push(self=ctx.stack, element=coinbase_address); + // See evm.cairo, pc is increased before entering the opcode + let opcode_number = [ctx.call_context.bytecode + ctx.program_counter - 1]; - // Update the execution context. - // Update context stack. - let ctx = ExecutionContext.update_stack(ctx, stack); - // Increment gas used. - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_COINBASE); - return ctx; - } + // To cast the codeoffset opcodes_label to a model.Opcode*, we need to use it to offset + // the current pc. We get the pc from the `get_fp_and_pc` util and assign a codeoffset (pc_label) to it. + // In short, this boilds down to: opcode = pc + offset - pc = offset + let (_, pc) = get_fp_and_pc(); - // @notice TIMESTAMP operation. - // @dev Get the block’s timestamp - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_timestamp{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - alloc_locals; + pc_label: + assert opcode = cast( + pc + (opcodes_label - pc_label) + (opcode_number - 0x40) * model.Opcode.SIZE, + model.Opcode*, + ); - if (ctx.stack.size == Constants.STACK_MAX_DEPTH) { - let (revert_reason_len, revert_reason) = Errors.stackOverflow(); + let out_of_gas = is_le(ctx.call_context.gas_limit, ctx.gas_used + opcode.gas - 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; } + assert range_check = range_check_ptr; - // Get the block’s timestamp - let (current_timestamp) = get_block_timestamp(); - let block_timestamp = Helpers.to_uint256(val=current_timestamp); - - let stack: model.Stack* = Stack.push(self=ctx.stack, element=block_timestamp); - - // Update the execution context. - // Update context stack. - let ctx = ExecutionContext.update_stack(ctx, stack); - // Increment gas used. - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_TIMESTAMP); - return ctx; - } - - // @notice NUMBER operation. - // @dev Get the block number - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_number{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - alloc_locals; - - 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; + if (opcode_number == 0x40) { + jmp blockhash; } - - // Get the block number. - let (current_block) = get_block_number(); - let block_number = Helpers.to_uint256(val=current_block); - - let stack: model.Stack* = Stack.push(self=ctx.stack, element=block_number); - - // Update the execution context. - // Update context stack. - let ctx = ExecutionContext.update_stack(ctx, stack); - // Increment gas used. - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_NUMBER); - return ctx; - } - - // @notice DIFFICULTY operation. - // @dev Get Difficulty - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_difficulty{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - 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; + if (opcode_number == 0x41) { + jmp coinbase; + } + if (opcode_number == 0x42) { + jmp timestamp; + } + if (opcode_number == 0x43) { + jmp number; + } + if (opcode_number == 0x44) { + jmp prevrandao; + } + if (opcode_number == 0x45) { + jmp gaslimit; + } + if (opcode_number == 0x46) { + jmp chainid; + } + if (opcode_number == 0x47) { + jmp selfbalance; + } + if (opcode_number == 0x48) { + jmp basefee; } - // Get the Difficulty. - let stack: model.Stack* = Stack.push_uint128(ctx.stack, 0); - - // Update the execution context. - // Update context stack. + blockhash: + let syscall_ptr = cast([fp - 7], felt*); + let pedersen_ptr = cast([fp - 6], HashBuiltin*); + let range_check_ptr = [fp]; + let ctx = cast([fp - 3], model.ExecutionContext*); + let (ctx, result) = Internals.blockhash(ctx); + jmp end; + + coinbase: + tempvar syscall_ptr = cast([fp - 7], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256( + 0xacdffe0cf08e20ed8ba10ea97a487004, 0x388ca486b82e20cc81965d056b4cdca + ); + jmp end; + + timestamp: + let syscall_ptr = cast([fp - 7], felt*); + let (block_timestamp) = get_block_timestamp(); + tempvar syscall_ptr = cast([ap - 2], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256(block_timestamp, 0); + jmp end; + + number: + let syscall_ptr = cast([fp - 7], felt*); + let (block_number) = get_block_number(); + tempvar syscall_ptr = cast([ap - 2], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256(block_number, 0); + jmp end; + + prevrandao: + tempvar syscall_ptr = cast([fp - 7], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256(0, 0); + jmp end; + + gaslimit: + let ctx = cast([fp - 3], model.ExecutionContext*); + tempvar gas_limit = ctx.call_context.gas_limit; + tempvar syscall_ptr = cast([fp - 7], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256(gas_limit, 0); + jmp end; + + chainid: + tempvar syscall_ptr = cast([fp - 7], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256(Constants.CHAIN_ID, 0); + jmp end; + + selfbalance: + let syscall_ptr = cast([fp - 7], felt*); + let pedersen_ptr = cast([fp - 6], HashBuiltin*); + let range_check_ptr = [fp]; + let ctx = cast([fp - 3], model.ExecutionContext*); + let (ctx, result) = Internals.selfbalance(ctx); + jmp end; + + basefee: + tempvar syscall_ptr = cast([fp - 7], felt*); + tempvar pedersen_ptr = cast([fp - 6], HashBuiltin*); + tempvar range_check_ptr = [fp]; + tempvar ctx = cast([fp - 3], model.ExecutionContext*); + tempvar result = Uint256(0, 0); + jmp end; + + end: + // Rebind unused args with fp + let opcode = cast([fp + 1], model.Opcode*); + let bitwise_ptr = cast([fp - 4], BitwiseBuiltin*); + + // Rebind used args with ap + let syscall_ptr = cast([ap - 6], felt*); + let pedersen_ptr = cast([ap - 5], HashBuiltin*); + let range_check_ptr = [ap - 4]; + let ctx = cast([ap - 3], model.ExecutionContext*); + let result = Uint256([ap - 2], [ap - 1]); + + // Finalize opcode + let stack = Stack.push_uint256(ctx.stack, result); let ctx = ExecutionContext.update_stack(ctx, stack); - // Increment gas used. - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_DIFFICULTY); + let ctx = ExecutionContext.increment_gas_used(ctx, opcode.gas); return ctx; } +} - // @notice GASLIMIT operation. - // @dev Get gas limit - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_gaslimit{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - // Get the Gas Limit - - if (ctx.stack.size == Constants.STACK_MAX_DEPTH) { - let (revert_reason_len, revert_reason) = Errors.stackOverflow(); +namespace Internals { + func blockhash{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + ctx: model.ExecutionContext* + ) -> (model.ExecutionContext*, Uint256) { + if (ctx.stack.size == 0) { + let (revert_reason_len, revert_reason) = Errors.stackUnderflow(); let ctx = ExecutionContext.stop(ctx, revert_reason_len, revert_reason, TRUE); - return ctx; + return (ctx, Uint256(0, 0)); } - let gas_limit = Helpers.to_uint256(val=ctx.call_context.gas_limit); - let stack: model.Stack* = Stack.push(self=ctx.stack, element=gas_limit); - - // Update the execution context. - // Update context stack. + let (stack, block_number_uint256) = Stack.pop(ctx.stack); let ctx = ExecutionContext.update_stack(ctx, stack); - // Increment gas used. - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_GASLIMIT); - return ctx; - } + let block_number = block_number_uint256.low; - // @notice CHAINID operation. - // @dev Get the chain ID. - // @custom:since Instanbul - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_chainid{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - // Get the chain ID. + // Check if blockNumber is within bounds by checking with current block number + // Valid range is the last 256 blocks (not including the current one) + let (current_block_number) = get_block_number(); + let in_range = is_in_range(block_number, current_block_number - 256, current_block_number); - 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; + // If not in range, return 0 + if (in_range == FALSE) { + return (ctx, Uint256(0, 0)); } - let stack: model.Stack* = Stack.push_uint128(ctx.stack, Constants.CHAIN_ID); - - // Update the execution context. - // Update context stack. - let ctx = ExecutionContext.update_stack(ctx, stack); - // Increment gas used. - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_CHAINID); - return ctx; + let (blockhash_registry_address_: felt) = blockhash_registry_address.read(); + let (blockhash_: felt) = IBlockhashRegistry.get_blockhash( + contract_address=blockhash_registry_address_, block_number=[block_number_uint256] + ); + let blockhash = Helpers.to_uint256(blockhash_); + return (ctx, [blockhash]); } - // @notice SELFBALANCE operation. - // @dev Get balance of currently executing contract - // @custom:since Istanbul - // @custom:group Block Information - // @custom:gas 5 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_selfbalance{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - alloc_locals; - // Get balance of current executing contract address balance and push to stack. - 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; - } - + func selfbalance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + ctx: model.ExecutionContext* + ) -> (model.ExecutionContext*, Uint256) { let (state, balance) = State.read_balance(ctx.state, ctx.call_context.address); - tempvar item = new Uint256(balance.low, balance.high); - let stack = Stack.push(ctx.stack, item); - - // Update the execution context. - let ctx = ExecutionContext.update_stack(ctx, stack); let ctx = ExecutionContext.update_state(ctx, state); - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_SELFBALANCE); - return ctx; - } - - // @notice BASEFEE operation. - // @dev Get base fee - // @custom:since Frontier - // @custom:group Block Information - // @custom:gas 2 - // @custom:stack_consumed_elements 0 - // @custom:stack_produced_elements 1 - // @param ctx The pointer to the execution context - // @return ExecutionContext The pointer to the updated execution context. - func exec_basefee{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(ctx: model.ExecutionContext*) -> model.ExecutionContext* { - // Get the base fee. - - let stack = Stack.push_uint128(self=ctx.stack, element=0); - - let ctx = ExecutionContext.update_stack(ctx, stack); - let ctx = ExecutionContext.increment_gas_used(self=ctx, inc_value=GAS_COST_BASEFEE); - - return ctx; + return (ctx, balance); } } + +// See model.Opcode +opcodes_label: +// BLOCKHASH +dw 20; // gas +dw 1; // stack_input +// COINBASE +dw 2; // gas +dw 0; // stack_input +// TIMESTAMP +dw 2; // gas +dw 0; // stack_input +// NUMBER +dw 2; // gas +dw 0; // stack_input +// PREVRANDAO +dw 2; // gas +dw 0; // stack_input +// GASLIMIT +dw 2; // gas +dw 0; // stack_input +// CHAINID +dw 2; // gas +dw 0; // stack_input +// SELFBALANCE +dw 5; // gas +dw 0; // stack_input +// BASEFEE +dw 2; // gas +dw 0; // stack_input diff --git a/src/kakarot/precompiles/precompiles.cairo b/src/kakarot/precompiles/precompiles.cairo index f8be9c433c..0e43631043 100644 --- a/src/kakarot/precompiles/precompiles.cairo +++ b/src/kakarot/precompiles/precompiles.cairo @@ -61,7 +61,7 @@ namespace Precompiles { calldata=cast(0, felt*), calldata_len=0, value=0, - gas_limit=Constants.TRANSACTION_GAS_LIMIT, + gas_limit=calling_context.call_context.gas_limit, gas_price=0, origin=calling_context.call_context.origin, calling_context=calling_context, diff --git a/src/kakarot/state.cairo b/src/kakarot/state.cairo index 811d547df0..11b5a54309 100644 --- a/src/kakarot/state.cairo +++ b/src/kakarot/state.cairo @@ -311,12 +311,9 @@ namespace State { // @dev Try to read from local dict, and read from ETH contract otherwise // @param self The pointer to the State // @param address The pointer to the Address - func read_balance{ - syscall_ptr: felt*, - pedersen_ptr: HashBuiltin*, - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - }(self: model.State*, address: model.Address*) -> (state: model.State*, balance: Uint256) { + func read_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.State*, address: model.Address* + ) -> (state: model.State*, balance: Uint256) { let balances = self.balances; let (pointer) = dict_read{dict_ptr=balances}(key=address.starknet); if (pointer != 0) { diff --git a/tests/src/kakarot/instructions/test_block_information.cairo b/tests/src/kakarot/instructions/test_block_information.cairo index 946bb0e54b..ebd9fec956 100644 --- a/tests/src/kakarot/instructions/test_block_information.cairo +++ b/tests/src/kakarot/instructions/test_block_information.cairo @@ -39,203 +39,33 @@ func constructor{ return (); } -@view -func test__blockhash_should_push_blockhash_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given # 1 - alloc_locals; - let fp_and_pc = get_fp_and_pc(); - local __fp__: felt* = fp_and_pc.fp_val; - - let (bytecode) = alloc(); - let stack = Stack.init(); - - let (local block_number_: Uint256) = block_number.read(); - - let stack = Stack.push(stack, &block_number_); - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = BlockInformation.exec_blockhash(ctx); - - // Then - assert result.gas_used = 20; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let (blockhash_) = blockhash.read(); - let value = Helpers.to_uint256(val=blockhash_); - assert_uint256_eq([index0], [value]); - - // Given # 2 - let (bytecode) = alloc(); - let stack = Stack.init(); - - let (current_block_number: felt) = get_block_number(); - let out_of_range_block = current_block_number - 260; - assert_nn(out_of_range_block); - let out_of_range_block_uint256 = Helpers.to_uint256(val=out_of_range_block); - let stack = Stack.push(stack, out_of_range_block_uint256); - let ctx = TestHelpers.init_context_with_stack(0, bytecode, stack); - - // When - let result = BlockInformation.exec_blockhash(ctx); - - // Then - assert result.gas_used = 20; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - assert index0.low = 0; - assert index0.high = 0; - - return (); -} - -@view -func test__chainId__should_push_chain_id_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given - alloc_locals; - let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); - - // When - let result = BlockInformation.exec_chainid(ctx); - - // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - assert index0.low = 1263227476; - assert index0.high = 0; - return (); -} - @external -func test__coinbase_should_push_coinbase_address_to_stack{ +func test__exec_block_information{ syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { +}(opcode: felt, stack_len: felt, stack: Uint256*) -> ( + result: Uint256, timestamp: felt, block_number: felt +) { // Given alloc_locals; let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); + assert [bytecode] = opcode; + let stack_ = Stack.init(); + if (stack_len != 0) { + let stack_ = Stack.push_uint256(stack_, stack[0]); + tempvar range_check_ptr = range_check_ptr; + } else { + let stack_ = stack_; + tempvar range_check_ptr = range_check_ptr; + } + let ctx = TestHelpers.init_context_with_stack(1, bytecode, stack_); + let ctx = ExecutionContext.increment_program_counter(ctx, 1); // When - let result = BlockInformation.exec_coinbase(ctx); + let ctx = BlockInformation.exec_block_information(ctx); // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let coinbase_address = Helpers.to_uint256(Constants.MOCK_COINBASE_ADDRESS); - assert_uint256_eq([index0], [coinbase_address]); - return (); -} - -@external -func test__timestamp_should_push_block_timestamp_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given - alloc_locals; - let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); - - // When - let result = BlockInformation.exec_timestamp(ctx); - - // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let (current_timestamp) = get_block_timestamp(); - let block_timestamp = Helpers.to_uint256(current_timestamp); - assert_uint256_eq([index0], [block_timestamp]); - return (); -} - -@external -func test__number_should_push_block_number_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given - alloc_locals; - let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); - - // When - let result = BlockInformation.exec_number(ctx); - - // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let (current_block) = get_block_number(); - let block_number = Helpers.to_uint256(current_block); - assert_uint256_eq([index0], [block_number]); - return (); -} - -@external -func test__gaslimit_should_push_gaslimit_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given - alloc_locals; - let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); - - // When - let result = BlockInformation.exec_gaslimit(ctx); - - // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let gas_limit = Helpers.to_uint256(Constants.TRANSACTION_GAS_LIMIT); - assert_uint256_eq([index0], [gas_limit]); - return (); -} - -@external -func test__difficulty_should_push_difficulty_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given - alloc_locals; - let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); - - // When - let result = BlockInformation.exec_difficulty(ctx); - - // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let difficulty = Helpers.to_uint256(0); - assert_uint256_eq([index0], [difficulty]); - return (); -} - -@external -func test__basefee_should_push_basefee_to_stack{ - syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* -}() { - // Given - alloc_locals; - let (bytecode) = alloc(); - let ctx = TestHelpers.init_context(0, bytecode); - - // When - let result = BlockInformation.exec_basefee(ctx); - - // Then - assert result.gas_used = 2; - assert result.stack.size = 1; - let (stack, index0) = Stack.peek(result.stack, 0); - let basefee = Helpers.to_uint256(0); - assert_uint256_eq([index0], [basefee]); - return (); + let (timestamp) = get_block_timestamp(); + let (block_number) = get_block_number(); + let (_, result) = Stack.peek(ctx.stack, 0); + return (result[0], timestamp, block_number); } diff --git a/tests/src/kakarot/instructions/test_block_information.py b/tests/src/kakarot/instructions/test_block_information.py index 6243e1ffc1..7138765e35 100644 --- a/tests/src/kakarot/instructions/test_block_information.py +++ b/tests/src/kakarot/instructions/test_block_information.py @@ -2,6 +2,7 @@ import pytest_asyncio from starkware.starknet.testing.contract import StarknetContract from starkware.starknet.testing.starknet import Starknet +from tests.utils.constants import Opcodes from tests.utils.uint256 import int_to_uint256 @@ -28,12 +29,53 @@ async def block_information( @pytest.mark.asyncio class TestBlockInformation: - async def test_everything_block(self, block_information): - await block_information.test__blockhash_should_push_blockhash_to_stack().call() - await block_information.test__chainId__should_push_chain_id_to_stack().call() - await block_information.test__coinbase_should_push_coinbase_address_to_stack().call() - await block_information.test__timestamp_should_push_block_timestamp_to_stack().call() - await block_information.test__number_should_push_block_number_to_stack().call() - await block_information.test__gaslimit_should_push_gaslimit_to_stack().call() - await block_information.test__difficulty_should_push_difficulty_to_stack().call() - await block_information.test__basefee_should_push_basefee_to_stack().call() + async def test__blockhash__should_return_hash_when_in_range( + self, block_information, blockhashes + ): + block_number = max(blockhashes["last_256_blocks"].keys()) + result = await block_information.test__exec_block_information( + Opcodes.BLOCKHASH, + [int_to_uint256(int(block_number))], + ).call() + assert result.result.result == int_to_uint256( + blockhashes["last_256_blocks"][block_number] + ) + + async def test__blockhash__should_return_0_when_out_of_range( + self, block_information, blockhashes + ): + block_number = max(blockhashes["last_256_blocks"].keys()) + result = await block_information.test__exec_block_information( + Opcodes.BLOCKHASH, + [int_to_uint256(int(block_number) - 260)], + ).call() + assert result.result.result == (0, 0) + + @pytest.mark.parametrize( + "opcode,expected_result", + [ + ( + Opcodes.COINBASE, + (0x388CA486B82E20CC81965D056B4CDCA, 0xACDFFE0CF08E20ED8BA10EA97A487004), + ), + (Opcodes.TIMESTAMP, ("{timestamp}", 0)), + (Opcodes.NUMBER, ("{block_number}", 0)), + (Opcodes.PREVRANDAO, (0, 0)), + (Opcodes.GASLIMIT, (1_000_000, 0)), + (Opcodes.CHAINID, (int.from_bytes(b"KKRT", "big"), 0)), + (Opcodes.BASEFEE, (0, 0)), + ], + ) + async def test__exec_block_information( + self, block_information, opcode, expected_result + ): + result, timestamp, block_number = ( + await block_information.test__exec_block_information(opcode, []).call() + ).result + expected_result = tuple( + v + if isinstance(v, int) + else int(v.format(timestamp=timestamp, block_number=block_number)) + for v in expected_result + ) + assert result == expected_result