defmodule BitcoinLib.Transaction.Validator do
@moduledoc """
Making sure transactions are valid
"""
alias BitcoinLib.Console
# alias BitcoinLib.Key.PublicKey
alias BitcoinLib.Transaction
# alias BitcoinLib.Transaction.{Input, Output}
# alias BitcoinLib.Script
alias BitcoinLib.Transaction.Validator.{Input, Preimage}
alias BitcoinLib.Transaction.Validator.Input, as: ValidatorInput
# alias BitcoinLib.Console
# ############ from signer, works right after creating the signature
# valid? =
# signature
# |> PublicKey.validate_signature(hashed_preimage, public_key)
# |> IO.inspect(label: "is signature valid?")
# ###########
@doc """
Validates a transaction
## Data from the signer's doctest
# transaction before signing: <<0x0100000001b62ba991789fb1739e6a17b3891fd94cfebf09a61fedb203d619932a4326c2e4000000001976a914afc3e518577316386188af748a816cd14ce333f288acffffffff0110270000000000002d76a9283265393261373463333431393661303236653839653061643561633431386366393430613361663288ac00000000::1040>>
# transaction after signing: <<0x0100000001b62ba991789fb1739e6a17b3891fd94cfebf09a61fedb203d619932a4326c2e4000000006a47304402207d2ff650acf4bd2f413dc04ded50fbbfc315bcb0aa97636b3c4caf55333d1c6a02207590f62363b2263b3d9b65dad3cd56e840e0d61dc0feab8f7e7956831c7e5103012102702ded1cca9816fa1a94787ffc6f3ace62cd3b63164f76d227d0935a33ee48c3ffffffff0110270000000000002d76a9283265393261373463333431393661303236653839653061643561633431386366393430613361663288ac00000000::1688>>
# public_key: <<0x02702ded1cca9816fa1a94787ffc6f3ace62cd3b63164f76d227d0935a33ee48c3::264>>
# signature: <<0x304402207d2ff650acf4bd2f413dc04ded50fbbfc315bcb0aa97636b3c4caf55333d1c6a02207590f62363b2263b3d9b65dad3cd56e840e0d61dc0feab8f7e7956831c7e5103::560>>
# sighash_type: 1
# preimage: <<0xee564327e1868240a2bbe3d3b445ac946a396de9802ede1ecaff0024f77eeca3::256>>
#### STEPS
# √ 1- decode transaction
# √ 2- extract signature
# √ 3- recreate preimage
# 4- validate input
## Examples
iex> "0100000001b62ba991789fb1739e6a17b3891fd94cfebf09a61fedb203d619932a4326c2e4000000006a47304402207d2ff650acf4bd2f413dc04ded50fbbfc315bcb0aa97636b3c4caf55333d1c6a02207590f62363b2263b3d9b65dad3cd56e840e0d61dc0feab8f7e7956831c7e5103012102702ded1cca9816fa1a94787ffc6f3ace62cd3b63164f76d227d0935a33ee48c3ffffffff0110270000000000002d76a9283265393261373463333431393661303236653839653061643561633431386366393430613361663288ac00000000"
...> |> BitcoinLib.Transaction.Validator.verify(prevouts, public_key)
true
"""
@spec verify(binary(), (binary() -> Transaction.t())) :: boolean()
def verify(txid, get_transaction_by_id) do
with {:ok, %Transaction{inputs: inputs} = transaction} <- get_transaction_by_id.(txid) do
[{:ok, validator_input}] =
inputs
|> Enum.map(&Input.validate(&1, get_transaction_by_id))
add_preimages(validator_input, transaction)
# {:ok, prevouts} <- Prevout.from_transaction(transaction, get_transaction_by_id) do
## {:ok, signatures} <- Signatures.from_transaction(transaction)
## [%{der_signature: der_signature, sighash_type: sighash_type}] = signatures
## preimage = Preimage.from_transaction(transaction, sighash_type)
# IO.inspect(prevouts, label: "prevouts")
## Console.print_hex(der_signature, "der_signature")
## Console.print_hex(preimage, "preimage")
else
{:error, message} -> {:error, message}
end
# signatures = get_signatures(transaction)
# Enum.zip_with(signatures, prevouts, &merge_signatures_and_prevouts/2)
# |> preimage(transaction)
true
end
def add_preimages(
%ValidatorInput{type: _type, der_signature: _der_signature, sighash_type: sighash_type},
%Transaction{} = transaction
) do
preimage = Preimage.from_transaction(transaction, sighash_type)
Console.print_hex(preimage, "preimage")
end
end