defmodule BitcoinLib.Transaction.Validator.Input do @moduledoc """ Validates a transaction input """ alias BitcoinLib.Crypto alias BitcoinLib.Script alias BitcoinLib.Transaction alias BitcoinLib.Transaction.{Input} alias BitcoinLib.Transaction.Validator.{Prevout, ScriptSig} alias BitcoinLib.Transaction.Validator.Input, as: ValidatorInput require Logger defstruct [:type, :der_signature, :sighash_type] @spec validate(Input.t(), (binary() -> Transaction.t())) :: {:ok, boolean()} | {:error, binary()} def validate(%Input{} = input, get_transaction_by_id) do with {:ok, output} <- Prevout.from_input(input, get_transaction_by_id) do case Script.identify(output.script_pub_key) do {:p2pkh, public_key_hash} -> validate_p2pkh(input, public_key_hash) other -> Logger.warning(inspect(other, label: "unknown prevout script type")) false end end end defp validate_p2pkh(input, public_key_hash) do with {:ok, %{public_key: public_key, der_signature: der_signature, sighash_type: sighash_type}} <- ScriptSig.p2pkh_from_input(input) do if public_key |> Crypto.hash160() == public_key_hash do { :ok, %ValidatorInput{type: :p2pkh, der_signature: der_signature, sighash_type: sighash_type} } else {:error, "public key and public key hash don't match"} end else {:error, message} -> {:error, message} end end end