def execute_transaction(t, header: nil, block_info: nil, ignore_exception: false)
      unless state.find_account(t.sender).balance >= t.gas_price * t.gas_limit + t.value
        raise InvalidTransaction.new('account balance not enough')
      end

      # remove gas fee from account balance
      state.add_balance(t.sender, -1 * t.gas_limit * t.gas_price)

      intrinsic_gas = fork_schema.intrinsic_gas_of_transaction(t)
      if intrinsic_gas > t.gas_limit
        raise InvalidTransaction.new('intrinsic gas overflowed gas limit')
      end

      gas_limit = t.gas_limit - intrinsic_gas

      instruction = Instruction.new(
        origin: t.sender,
        price: t.gas_price,
        sender: t.sender,
        value: t.value,
        header: header,
      )

      if t.contract_creation?
        instruction.bytes_code = t.data
      else
        instruction.bytes_code = get_account_code(t.to)
        instruction.address = t.to
        instruction.data = t.data
      end

      block_info ||= header && BlockInfo.from_header(header)
      context = Ciri::EVM::ExecutionContext.new(
        instruction: instruction, gas_limit: gas_limit,
        block_info: block_info, fork_schema: fork_schema
      )
      vm = Ciri::EVM::VM.new(state: state, chain: @chain, burn_gas_on_exception: true)

      unless instruction.value > state.find_account(instruction.sender).balance
        state.increment_nonce(instruction.sender)
      end

      vm.with_context(context) do
        if t.contract_creation?
          # contract creation
          vm.create_contract(context: context)
        else
          vm.call_message(context: context)
        end
        raise context.exception if !ignore_exception && context.exception

        # refund gas
        sub_state_refund_gas = fork_schema.calculate_refund_gas(vm)
        context.refund_gas(sub_state_refund_gas)
        refund_gas = context.reset_refund_gas
        remain_gas = context.remain_gas
        actually_gas_used = t.gas_limit - remain_gas
        actually_refund_gas = [refund_gas, actually_gas_used / 2].min
        refund_gas_amount = (actually_refund_gas + remain_gas) * t.gas_price
        debug("Transaction refund #{refund_gas_amount} to #{t.sender.to_s.hex}")
        state.add_balance(t.sender, refund_gas_amount)

        # gas_used after refund gas
        gas_used = actually_gas_used - actually_refund_gas

        # miner fee
        fee = gas_used * t.gas_price
        debug("Transaction fee #{fee}")
        miner_account = find_account(block_info.coinbase)
        miner_account.balance += fee
        state.set_balance(block_info.coinbase, miner_account.balance)

        # EIP158 fork, we need to delete miner account if account become empty
        vm.sub_state.add_touched_account(block_info.coinbase)
        vm.delete_empty_accounts

        # destroy accounts
        vm.execution_context.all_suicide_accounts.each do |address|
          state.set_balance(address, 0)
          state.delete_account(address)
        end

        ExecutionResult.new(status: context.status, state_root: state_root, logs: context.all_log_series,
                            gas_used: gas_used, gas_price: t.gas_price, exception: context.exception,
                            output: context.output)
      end
    end
def execute_transaction(t, header: nil, block_info: nil, ignore_exception: false)
      unless state.find_account(t.sender).balance >= t.gas_price * t.gas_limit + t.value
        raise InvalidTransaction.new('account balance not enough')
      end

      # remove gas fee from account balance
      state.add_balance(t.sender, -1 * t.gas_limit * t.gas_price)

      intrinsic_gas = fork_schema.intrinsic_gas_of_transaction(t)
      if intrinsic_gas > t.gas_limit
        raise InvalidTransaction.new('intrinsic gas overflowed gas limit')
      end

      gas_limit = t.gas_limit - intrinsic_gas

      instruction = Instruction.new(
        origin: t.sender,
        price: t.gas_price,
        sender: t.sender,
        value: t.value,
        header: header,
      )

      if t.contract_creation?
        instruction.bytes_code = t.data
      else
        instruction.bytes_code = get_account_code(t.to)
        instruction.address = t.to
        instruction.data = t.data
      end

      block_info ||= header && BlockInfo.from_header(header)
      context = Ciri::EVM::ExecutionContext.new(
        instruction: instruction, gas_limit: gas_limit,
        block_info: block_info, fork_schema: fork_schema
      )
      vm = Ciri::EVM::VM.new(state: state, chain: @chain, burn_gas_on_exception: true)

      unless instruction.value > state.find_account(instruction.sender).balance
        state.increment_nonce(instruction.sender)
      end

      vm.with_context(context) do
        if t.contract_creation?
          # contract creation
          vm.create_contract(context: context)
        else
          vm.call_message(context: context)
        end
        raise context.exception if !ignore_exception && context.exception

        # refund gas
        sub_state_refund_gas = fork_schema.calculate_refund_gas(vm)
        context.refund_gas(sub_state_refund_gas)
        refund_gas = context.reset_refund_gas
        remain_gas = context.remain_gas
        actually_gas_used = t.gas_limit - remain_gas
        actually_refund_gas = [refund_gas, actually_gas_used / 2].min
        refund_gas_amount = (actually_refund_gas + remain_gas) * t.gas_price
        debug("Transaction refund #{refund_gas_amount} to #{t.sender.to_s.hex}")
        state.add_balance(t.sender, refund_gas_amount)

        # gas_used after refund gas
        gas_used = actually_gas_used - actually_refund_gas

        # miner fee
        fee = gas_used * t.gas_price
        debug("Transaction fee #{fee}")
        miner_account = find_account(block_info.coinbase)
        miner_account.balance += fee
        state.set_balance(block_info.coinbase, miner_account.balance)

        # EIP158 fork, we need to delete miner account if account become empty
        vm.sub_state.add_touched_account(block_info.coinbase)
        vm.delete_empty_accounts

        # destroy accounts
        vm.execution_context.all_suicide_accounts.each do |address|
          state.set_balance(address, 0)
          state.delete_account(address)
        end

        ExecutionResult.new(status: context.status, state_root: state_root, logs: context.all_log_series,
                            gas_used: gas_used, gas_price: t.gas_price, exception: context.exception,
                            output: context.output)
      end
    end
execute transaction
 @param t Transaction
 @param header Chain::Header