< Summary

Information
Class: EF.Blockchain.Domain.TransactionInput
Assembly: EF.Blockchain.Domain
File(s): C:\dev\@web3\web3-001-ef-blockchain\backend\EF.Blockchain\src\EF.Blockchain.Domain\TransactionInput.cs
Line coverage
100%
Covered lines: 57
Uncovered lines: 0
Coverable lines: 57
Total lines: 130
Line coverage: 100%
Branch coverage
100%
Covered branches: 14
Total branches: 14
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_FromAddress()100%11100%
get_Amount()100%11100%
get_Signature()100%11100%
get_PreviousTx()100%11100%
.ctor(...)100%11100%
.ctor(...)100%66100%
GetHash()100%11100%
Sign(...)100%11100%
IsValid()100%88100%
FromTxo(...)100%11100%

File(s)

C:\dev\@web3\web3-001-ef-blockchain\backend\EF.Blockchain\src\EF.Blockchain.Domain\TransactionInput.cs

#LineLine coverage
 1using NBitcoin;
 2using NBitcoin.Crypto;
 3using System.Security.Cryptography;
 4using System.Text;
 5using System.Text.Json.Serialization;
 6
 7namespace EF.Blockchain.Domain;
 8
 9/// <summary>
 10/// Represents an input in a blockchain transaction, including signature validation and ownership of funds.
 11/// </summary>
 12public class TransactionInput
 13{
 14    /// <summary>
 15    /// Public key (hex) of the sender.
 16    /// </summary>
 170417    public string FromAddress { get; private set; }
 18
 19    /// <summary>
 20    /// Amount of coins being transferred from this input.
 21    /// </summary>
 184822    public int Amount { get; private set; }
 23
 24    /// <summary>
 25    /// Signature proving ownership of the referenced output.
 26    /// </summary>
 300827    public string Signature { get; private set; }
 28
 29    /// <summary>
 30    /// The hash of the previous transaction output being referenced.
 31    /// </summary>
 196832    public string PreviousTx { get; private set; }
 33
 34    /// <summary>
 35    /// Constructor used for deserialization.
 36    /// </summary>
 37    [JsonConstructor]
 5638    public TransactionInput(string fromAddress, int amount, string signature, string previousTx)
 5639    {
 5640        FromAddress = fromAddress;
 5641        Amount = amount;
 5642        Signature = signature;
 5643        PreviousTx = previousTx;
 5644    }
 45
 46    /// <summary>
 47    /// Creates a new transaction input with optional values.
 48    /// </summary>
 65649    public TransactionInput(string? fromAddress = null, int? amount = null, string? signature = null, string? previousTx
 65650    {
 65651        FromAddress = fromAddress ?? string.Empty;
 65652        Amount = amount ?? 0;
 65653        Signature = signature ?? string.Empty;
 65654        PreviousTx = previousTx ?? string.Empty;
 65655    }
 56
 57    /// <summary>
 58    /// Computes a SHA-256 hash of this transaction input.
 59    /// </summary>
 60    /// <returns>The lowercase hex hash string.</returns>
 61    public string GetHash()
 68062    {
 68063        var raw = $"{PreviousTx}{FromAddress}{Amount}";
 68064        using var sha256 = SHA256.Create();
 68065        var bytes = Encoding.UTF8.GetBytes(raw);
 68066        var hashBytes = sha256.ComputeHash(bytes);
 68067        return Convert.ToHexString(hashBytes).ToLower();
 68068    }
 69
 70    /// <summary>
 71    /// Signs this transaction input using the sender's private key.
 72    /// </summary>
 73    /// <param name="privateKeyHex">The sender's private key in hex format.</param>
 74    public void Sign(string privateKeyHex)
 51275    {
 51276        var privateKeyBytes = Convert.FromHexString(privateKeyHex);
 51277        var key = new Key(privateKeyBytes);
 78
 51279        var hashHex = GetHash();
 51280        var hashBytes = Convert.FromHexString(hashHex);
 51281        var signature = key.Sign(new uint256(hashBytes));
 82
 51283        Signature = Convert.ToHexString(signature.ToDER());
 51284    }
 85
 86    /// <summary>
 87    /// Validates the transaction input by checking the digital signature.
 88    /// </summary>
 89    /// <returns>A <see cref="Validation"/> result indicating success or failure.</returns>
 90    public Validation IsValid()
 48091    {
 48092        if (string.IsNullOrWhiteSpace(Signature) || string.IsNullOrWhiteSpace(PreviousTx))
 28893            return new Validation(false, "Signature and previous TX are required");
 94
 19295        if (Amount < 1)
 1696            return new Validation(false, "Amount must be greater than zero");
 97
 98        try
 17699        {
 176100            var pubKeyBytes = Convert.FromHexString(FromAddress);
 168101            var pubKey = new PubKey(pubKeyBytes);
 102
 168103            var hashBytes = Convert.FromHexString(GetHash());
 168104            var signatureBytes = Convert.FromHexString(Signature);
 168105            var ecdsaSig = ECDSASignature.FromDER(signatureBytes);
 106
 168107            bool isValid = pubKey.Verify(new uint256(hashBytes), ecdsaSig);
 108
 168109            return isValid ? new Validation() : new Validation(false, "Invalid tx input signature");
 110        }
 8111        catch
 8112        {
 8113            return new Validation(false, "Error verifying signature");
 114        }
 480115    }
 116
 117    /// <summary>
 118    /// Creates a new <see cref="TransactionInput"/> from a given <see cref="TransactionOutput"/>.
 119    /// </summary>
 120    /// <param name="txo">The transaction output to reference.</param>
 121    /// <returns>A new input referencing the output.</returns>
 122    public static TransactionInput FromTxo(TransactionOutput txo)
 8123    {
 8124        return new TransactionInput(
 8125            fromAddress: txo.ToAddress,
 8126            amount: txo.Amount,
 8127            previousTx: txo.Tx
 8128        );
 8129    }
 130}