defmodule EVM.Operation.BlockInformation do alias EVM.Operation alias EVM.Interface.BlockInterface @doc """ Get the hash of one of the 256 most recent complete blocks. # TODO: Test 256 limit ## Examples iex> block_b = %Block.Header{number: 2, mix_hash: "block_b"} iex> block_a = %Block.Header{number: 1, mix_hash: "block_a"} iex> genesis_block = %Block.Header{number: 0, mix_hash: <<0x00::256>>} iex> block_map = %{<<0x00::256>> => genesis_block, "block_a" => block_a, "block_b" => block_b} iex> block_interface = EVM.Interface.Mock.MockBlockInterface.new(block_b, block_map) iex> exec_env = %EVM.ExecEnv{block_interface: block_interface} iex> EVM.Operation.BlockInformation.blockhash([3], %{exec_env: exec_env}) 0 iex> EVM.Operation.BlockInformation.blockhash([2], %{exec_env: exec_env}) "block_b" iex> EVM.Operation.BlockInformation.blockhash([1], %{exec_env: exec_env}) "block_a" iex> EVM.Operation.BlockInformation.blockhash([0], %{exec_env: exec_env}) <<0::256>> iex> EVM.Operation.BlockInformation.blockhash([-1], %{exec_env: exec_env}) 0 """ @spec blockhash(Operation.stack_args, Operation.vm_map) :: Operation.op_result def blockhash([block_number], %{exec_env: exec_env}) do block_difference = exec_env.block_interface.block_header.number - block_number if block_difference > 256 || block_difference < 0 do 0 else block_header = BlockInterface.get_block_by_number(exec_env.block_interface, block_number) if block_header, do: block_header.mix_hash, else: 0 end end @doc """ Get the block's beneficiary address. ## Examples iex> block_interface = EVM.Interface.Mock.MockBlockInterface.new(%Block.Header{beneficiary: <<0x55::160>>}) iex> exec_env = %EVM.ExecEnv{block_interface: block_interface} iex> EVM.Operation.BlockInformation.coinbase([], %{exec_env: exec_env}) <<0x55::160>> """ @spec coinbase(Operation.stack_args, Operation.vm_map) :: Operation.op_result def coinbase(_args, %{exec_env: exec_env}) do block_header = BlockInterface.get_block_header(exec_env.block_interface) block_header.beneficiary end @doc """ Get the block's timestamp ## Examples iex> block_interface = EVM.Interface.Mock.MockBlockInterface.new(%Block.Header{timestamp: 1_000_000}) iex> exec_env = %EVM.ExecEnv{block_interface: block_interface} iex> EVM.Operation.BlockInformation.timestamp([], %{exec_env: exec_env}) 1_000_000 """ @spec timestamp(Operation.stack_args, Operation.vm_map) :: Operation.op_result def timestamp(_args, %{exec_env: exec_env}) do block_header = BlockInterface.get_block_header(exec_env.block_interface) block_header.timestamp end @doc """ Get the block's number ## Examples iex> block_interface = EVM.Interface.Mock.MockBlockInterface.new(%Block.Header{number: 1_500_000}) iex> exec_env = %EVM.ExecEnv{block_interface: block_interface} iex> EVM.Operation.BlockInformation.number([], %{exec_env: exec_env}) 1_500_000 """ @spec number(Operation.stack_args, Operation.vm_map) :: Operation.op_result def number(_args, %{exec_env: exec_env}) do block_header = BlockInterface.get_block_header(exec_env.block_interface) block_header.number end @doc """ Get the block's difficulty ## Examples iex> block_interface = EVM.Interface.Mock.MockBlockInterface.new(%Block.Header{difficulty: 2_000_000}) iex> exec_env = %EVM.ExecEnv{block_interface: block_interface} iex> EVM.Operation.BlockInformation.difficulty([], %{exec_env: exec_env}) 2_000_000 """ @spec difficulty(Operation.stack_args, Operation.vm_map) :: Operation.op_result def difficulty(_args, %{exec_env: exec_env}) do block_header = BlockInterface.get_block_header(exec_env.block_interface) block_header.difficulty end @doc """ Get the block's gas limit. ## Examples iex> block_interface = EVM.Interface.Mock.MockBlockInterface.new(%Block.Header{gas_limit: 3_000_000}) iex> exec_env = %EVM.ExecEnv{block_interface: block_interface} iex> EVM.Operation.BlockInformation.gaslimit([], %{exec_env: exec_env}) 3_000_000 """ @spec gaslimit(Operation.stack_args, Operation.vm_map) :: Operation.op_result def gaslimit(_args, %{exec_env: exec_env}) do block_header = BlockInterface.get_block_header(exec_env.block_interface) block_header.gas_limit end end