lib/script/opcodes/bitwise_logic/equal.ex

defmodule BitcoinLib.Script.Opcodes.BitwiseLogic.Equal do
  @moduledoc """
  Based on https://en.bitcoin.it/wiki/Script#Bitwise_logic

  Word OP_EQUAL
  Opcode 135
  Hex 0x87
  Input x1 x2
  Output True / false
  Description Returns 1 if the inputs are exactly equal, 0 otherwise
  """

  @behaviour BitcoinLib.Script.Opcode

  alias BitcoinLib.Script.Opcodes.BitwiseLogic.Equal

  defstruct []

  @value 0x87

  @doc """
  Returns 0x87

  ## Examples
      iex> BitcoinLib.Script.Opcodes.BitwiseLogic.Equal.v()
      0x87
  """
  @spec v() :: 0x87
  def v do
    @value
  end

  @doc """
  Returns <<0x87>>

  ## Examples
      iex> BitcoinLib.Script.Opcodes.BitwiseLogic.Equal.encode()
      <<0x87>>
  """
  @spec encode() :: <<_::8>>
  def encode() do
    <<@value::8>>
  end

  @doc """
  Returns 1 if the inputs are exactly equal, 0 otherwise.

  ## Examples
      iex> BitcoinLib.Script.Opcodes.BitwiseLogic.Equal.execute(
      ...>   %BitcoinLib.Script.Opcodes.BitwiseLogic.Equal{},
      ...>   [3, 3, 4]
      ...> )
      {:ok, [1, 4]}
  """
  @spec execute(%Equal{}, list()) ::
          {:ok, [1 | list()]} | {:ok, [0 | list()]} | {:error, binary()}
  def execute(_opcode, []), do: {:error, "trying to execute OP_EQUAL on an empty stack"}

  def execute(_opcode, [element | []]),
    do: {:error, "trying to execute OP_EQUAL on a stack with a single element #{element}"}

  def execute(_opcode, [first_element | [second_element | remaining]]) do
    case first_element == second_element do
      true -> {:ok, [1 | remaining]}
      false -> {:ok, [0 | remaining]}
    end
  end
end