Blockchain implementation in F#: Wallet


Introduction

This is Part 3 of my F# blockchain implementation. Previous parts:

  1. Block and Blockchain
  2. Transactions

Code

In this part I am implementing a wallet functionality. The code is based on a JavaScript blockchain implementation called naivecoin. The source code for naivecoin transactions can be found here.

namespace Blockchain.Core  open System.Security.Cryptography  open Helpers  type Wallet() =     let keyName = "blockchain"      let key =         if CngKey.Exists(keyName) then              CngKey.Open(keyName)         else             CngKey.Create(CngAlgorithm.ECDsaP521, keyName)      member this.Address = key.Export(CngKeyBlobFormat.EccPublicBlob).ToHex()      member private this.GetBalance(address: string, unspentOutputs: UnspentTransactionOutput seq) =         unspentOutputs         |> Seq.filter (fun x -> x.address = address)         |> Seq.map (fun x -> x.amount)         |> Seq.fold (+) 0.0      member private this.FindOutputsWithChangeForTransaction(transactionAmount: float, unspentOutputs: UnspentTransactionOutput seq) =         let rec findOutputsWithChange currentAmount (unspentOutputs : UnspentTransactionOutput seq) (consumedOutputs : UnspentTransactionOutput seq) =             if currentAmount >= transactionAmount then                 (consumedOutputs, currentAmount - transactionAmount)             else if Seq.isEmpty unspentOutputs then                 failwith "Not enough coins to send transaction."             else                 let currentOutput = unspentOutputs |> Seq.head                 findOutputsWithChange (currentAmount + currentOutput.amount) (unspentOutputs |> Seq.skip 1) (consumedOutputs |> Seq.append [| currentOutput |])          findOutputsWithChange 0.0 unspentOutputs []           member private this.CreateOutputs(receiverAddress: string, amount: float, change: float) =         if change = 0.0 then             Seq.ofArray [| { address = receiverAddress; amount = amount } |]          else             Seq.ofArray [| { address = receiverAddress; amount = amount}; { address = this.Address; amount = change } |]      member this.CreateTransaction(receiverAddress: string, amount: float, unspentOutputs: UnspentTransactionOutput seq) =         let myUnspentOutputs = unspentOutputs |> Seq.filter (fun x -> x.address = this.Address)         let (consumedOutputs, change) = this.FindOutputsWithChangeForTransaction(amount, myUnspentOutputs)         let unsignedInputs = consumedOutputs |> Seq.map (fun x -> { sourceOutputTransactionId = x.transactionId; sourceOutputIndex = x.outputIndex; signature = "" })         let outputs = this.CreateOutputs(receiverAddress, amount, change)         let processor = new TransactionProcessor()         let transactionId = processor.GetTransactionId(unsignedInputs, outputs)         let tempTransaction = { id = transactionId; inputs = unsignedInputs |> Array.ofSeq; outputs = outputs |> Array.ofSeq }         let inputs = unsignedInputs |> Seq.mapi (fun i x -> { x with signature = processor.SignTransactionInput(tempTransaction, i, key, myUnspentOutputs) })         { tempTransaction with inputs = inputs |> Array.ofSeq }