4 people like it.

Using NBitcoin to create private BlockChain with F# (FSharp)

This is just an initial example / tech-demo.

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
183: 
184: 
185: 
186: 
187: 
188: 
189: 
190: 
191: 
192: 
193: 
194: 
195: 
196: 
197: 
198: 
199: 
200: 
201: 
202: 
203: 
204: 
205: 
206: 
207: 
208: 
209: 
210: 
211: 
212: 
213: 
214: 
215: 
216: 
217: 
218: 
219: 
220: 
221: 
222: 
223: 
224: 
225: 
226: 
227: 
228: 
229: 
230: 
231: 
232: 
233: 
234: 
235: 
236: 
237: 
238: 
239: 
240: 
241: 
242: 
243: 
244: 
245: 
246: 
247: 
248: 
249: 
250: 
251: 
252: 
253: 
254: 
255: 
256: 
257: 
258: 
259: 
260: 
261: 
262: 
263: 
264: 
265: 
266: 
267: 
268: 
269: 
270: 
271: 
272: 
273: 
274: 
275: 
276: 
277: 
278: 
279: 
280: 
281: 
282: 
283: 
284: 
285: 
286: 
287: 
288: 
289: 
290: 
291: 
292: 
293: 
294: 
295: 
296: 
297: 
298: 
299: 
300: 
301: 
302: 
303: 
304: 
305: 
306: 
307: 
308: 
309: 
310: 
311: 
312: 
313: 
314: 
315: 
316: 
317: 
318: 
319: 
320: 
321: 
322: 
#if INTERACTIVE
#I "./../packages/NBitcoin/lib/net45/"
#I "./../packages/Newtonsoft.Json/lib/net45"
#r "NBitcoin.dll"
#r "Newtonsoft.Json.dll"
#else
module BlockChain
#endif

open System
open NBitcoin
open NBitcoin.Protocol

// -------------- GENERAL BLOCKCHAIN NETWORK SETTINGS -------------- //

let network = 
    // Select your network
    // Network.Main
    // Network.Test

    // Or create your own:
        let builder = NetworkBuilder()
        builder.CopyFrom Network.Main
        let genesis = Network.Main.GetGenesis()
        //builder.SetGenesis( {genesis.Header.UpdateTime with Ti }
        builder.SetName("MyBlockChain").BuildAndRegister()

/// Generate a new wallet private key for a new user as byte array
let getNewPrivateKey() = Key().ToBytes()

/// Create BitcoinSecret from byte array
let getSecret(bytes:byte[]) = BitcoinSecret(Key(bytes), network)


// --------- CUSTOM BLOCKCHAIN AND ITS COMPLEXITY --------- //

/// Complexity of valid mining. Genesis is having 10.
/// But this comes down to how much resources you are willing to
/// spend to validate blockchain. Note: Some part of blockchain
/// security comes from the fact that valid hashes are not so easy
/// to calculate, making the generation of alternative valid blockchain slow.
let leadingZeros = "0000"

/// Validation of blockchain hashes.
type BlockChainCheck =
/// No validation
| NoWork
/// Validation of leadingZeros amount only
| EasyWork
/// Default Bitcoin level validation
| CorrectWork

/// The normal bitcoin validation is 8 leading zeros in hashcodes
/// That makes mining taking a lot of resources. So this is more
/// light weight option to mining.
type ChainedBlock with
  /// Re-implementation of Validate()
  member cb.ValidateEasy(network:Network) =
    let genesis = cb.Height = 0
    if (not genesis) && cb.Previous = null then false
    else
    let heightCorrect = genesis || cb.Height = cb.Previous.Height + 1
    let genesisCorrect = 
        (not genesis) || cb.HashBlock = network.GetGenesis().GetHash()
    let hashPrevCorrect = 
        genesis || cb.Header.HashPrevBlock = cb.Previous.HashBlock
    let hashCorrect = cb.HashBlock = cb.Header.GetHash()
    let workCorrect = 
        genesis || cb.Header.GetHash().ToString().StartsWith leadingZeros
    
    heightCorrect && genesisCorrect && hashPrevCorrect
    && hashCorrect && workCorrect
   
type ChainBase with
  /// Re-implementation of Validate()
  member cb.ValidateEasy(network:Network, ?fullChain) =
    let tip = cb.Tip
    if tip = null then false
    else
    match fullChain with
    | None | Some true ->
        let anyFails = 
            tip.EnumerateToGenesis() 
            |> Seq.exists(fun block -> not(block.ValidateEasy network))
        not anyFails
    | Some false ->
        tip.ValidateEasy network


/// This will mine the correct hash. 
/// Performance is not optimized: if you would really want to do
/// mining, you would probably want to use some more parallel algorithm.
let ``mine to correct`` checkType (chain:ConcurrentChain) (block:Block) =
    let validation = 
        match checkType with
        | NoWork -> fun (cb:ChainedBlock) -> true
        | EasyWork -> fun cb -> cb.ValidateEasy network
        | CorrectWork -> fun cb -> cb.Validate network 

    let rec mine nonce =
        block.Header.Nonce <- nonce
        let headerBlock = 
            ChainedBlock(block.Header, block.Header.GetHash(), 
                         chain.GetBlock(block.Header.HashPrevBlock))
        if validation headerBlock then ()
        else mine (nonce+1u)
    mine 0u

/// Attach a block to chain
let ``attach to chain`` (checkType:BlockChainCheck) (chain:ConcurrentChain) (block:Block) =
    let header = block.Header
    header.HashPrevBlock <- chain.Tip.HashBlock
    header.Bits <- 
        //header.GetWorkRequired(network, chain.Tip)
        chain.Tip.GetWorkRequired(network)
    header.BlockTime <- DateTimeOffset.UtcNow
    header.Nonce <- RandomUtils.GetUInt32()
    //header.UpdateTime(network, chain.Tip)
    block.UpdateMerkleRoot()
    ``mine to correct`` checkType chain block
    chain.SetTip header |> ignore
    chain.GetBlock(header.GetHash())


/// Attach a bunch of transactions to a new block
let ``to new block`` txs =
    let block = Block()
    txs |> Seq.iter (block.AddTransaction >> ignore)
    block.UpdateMerkleRoot()
    block
    
// --------- TRANSACTIONS --------- //

/// No fees on our custom block-chain
/// Consifer adding some fee when you want users to do the mining.
let noFees = Unchecked.defaultof<FeeRate>
let txBuilder() = 
    let b = TransactionBuilder()
    b.StandardTransactionPolicy.MinRelayTxFee <- FeeRate.Zero
    b

/// Coinbase transaction is a transaction to generate money to our system.
let ``give money`` (toUser:BitcoinSecret) (sum:int) =
    let money = Money sum
    let coin = 
        Coin( // Coins for sums, ColoredCoins for assets
              // This is a coinbase / generation transaction, so hash is zero:
            OutPoint(), TxOut(money, toUser.PubKey.ScriptPubKey)
        )
    let builder = txBuilder()
    let tx =
        builder
            //.IssueAsset(toUser, OpenAsset.AssetMoney(asset.AssetId, quantity))
            .AddCoins([| (coin :> ICoin) |])
            .AddKeys(toUser)
            .Send(toUser, money)
            .SetChange(toUser.GetAddress())
            .BuildTransaction(true)

    if not tx.IsCoinBase then 
        failwith "Was not a coinbase transaction"

    let ok, errs = builder.Verify(tx, noFees)
    match ok with
    | true -> tx
    | false -> failwith(String.Join(",", errs))

/// Normal transaction to transfer money / asset from user to next user. 
/// Needs outpoint from previous transaction to make a block chain.
let ``spend money`` (coins:Coin list) (fromUser:BitcoinSecret) (toUser:BitcoinPubKeyAddress) (sum:int) =
    let money = Money sum
    let fees = Money.Zero
    let coinsArr = 
        coins 
        |> List.filter(fun c -> c.TxOut.IsTo fromUser)
        |> List.map(fun c -> c :> ICoin) |> List.toArray
    let builder = txBuilder()
    let tx =
        builder
            .AddCoins(coinsArr)
            .AddKeys(fromUser)
            .Send(toUser, (money - fees))
            .SendFees(fees)
            .SetChange(fromUser.GetAddress())
            .BuildTransaction(true)
    let ok, errs = builder.Verify(tx, noFees)
    match ok with
    | true -> tx
    | false -> failwith(String.Join(",", errs))

// --------- SOME HELPER FUNCTIONS --------- //

/// Create a new user
let makeUser() = 
    let user = BitcoinSecret(Key(), network)
    Console.WriteLine "Store users private key to a cold dry place and never show it to anyone:"
    network |> user.PrivateKey.GetWif |> Console.WriteLine
    user

/// Get coins from transaction
let ``fetch coins of`` dest (tx:Transaction) =
     tx.Outputs 
     |> Seq.mapi(fun idx op -> idx,op)
     |> Seq.filter(fun (_,op) -> op.Value > Money.Zero && op.IsTo(dest)) 
     |> Seq.map(fun (idx,op) ->
         Coin(OutPoint(tx, idx), op)
     ) |> Seq.toList

let ``save tracker`` filename (tracker:NBitcoin.SPV.Tracker) =
    let filterBefore = tracker.CreateBloomFilter(0.005)
    use fileStream = System.IO.File.Create filename
    tracker.Save fileStream

let ``load tracker`` filename =
    let tracker = 
        filename |> System.IO.File.OpenRead
        |> NBitcoin.SPV.Tracker.Load
    if not(tracker.Validate()) then failwith "Not valid tracker"
    else tracker

let ``save chain`` filename (chain:ConcurrentChain) =
    use fileStream = System.IO.File.Create filename
    chain.WriteTo (BitcoinStream(fileStream, true))

let ``load chain`` filename =
    let chain = new ConcurrentChain(network)
    filename |> System.IO.File.ReadAllBytes |> chain.Load
    // if not(chain.Validate network) then failwith "Not valid"
    if not(chain.ValidateEasy network) then failwith "Not valid chain"
    else chain

// --------- TESTING --------- //
let testing() =

    // A block chain, and a tracker
    let chain = new ConcurrentChain(network)
    let tracker = NBitcoin.SPV.Tracker()
    
    // make some users
    let thomas = makeUser()
    let antero = makeUser()
    let john = makeUser()

    tracker.Add(thomas)
    tracker.Add(antero)
    tracker.Add(john)

    // Make Block 1 with transactions and add it to chain
    let coinbase1 = ``give money`` thomas 1000

    let coins1 = coinbase1 |> ``fetch coins of`` thomas
    let transfer1 = 
        ``spend money`` coins1 thomas (antero.GetAddress()) 500

    let coins2 = transfer1 |> ``fetch coins of`` thomas
    let transfer2 = ``spend money`` coins2 thomas (john.GetAddress()) 300

    let block1 = 
        [coinbase1; transfer1; transfer2] 
        |> ``to new block`` 
    
    let chained1 = 
        block1 |> ``attach to chain`` BlockChainCheck.EasyWork chain

    block1.Transactions |> Seq.iter (fun tx -> 
        tracker.NotifyTransaction(tx, chained1, block1) |> ignore)
        
    // Check that chain and the tracker are valid:
    let ``chain ok`` = chain.ValidateEasy(network)
    let ``tracker ok`` = tracker.Validate()
    let transactions1 = tracker.GetWalletTransactions(chain)
    //transactions1.GetSpendableCoins()
    //transactions1.Summary.Confirmed
    // Thomas: 200, Antero: 500, John: 300

    // Make Block 2 with transactions and add it to chain

    let coinbase2 = ``give money`` thomas 100

    let coins3 = transfer1 |> ``fetch coins of`` antero
    let transfer3 = ``spend money`` coins3 antero (john.GetAddress()) 500

    let coins4 = 
        (transfer2 |> ``fetch coins of`` thomas) @
        (coinbase2 |> ``fetch coins of`` thomas)

    let transfer4 = 
        ``spend money`` coins4 thomas (john.GetAddress()) 250

    //let coins5 = transfer4 |> ``fetch coins of`` thomas 
    let block2 = 
        [coinbase2; transfer3; transfer4] 
        |> ``to new block`` 

    let chained2 = 
        block2 |> ``attach to chain`` BlockChainCheck.EasyWork chain

    block2.Transactions |> Seq.iter (fun tx -> 
        tracker.NotifyTransaction(tx, chained2, block2) |> ignore)
    
    // Check the validity of the chain and the tracker
    let ``chain still ok`` = chain.ValidateEasy(network)
    let ``tracker still ok`` = tracker.Validate()
    let transactions2 = tracker.GetWalletTransactions(chain)
    let ``available coins`` = transactions2.GetSpendableCoins() |> Seq.toList
    // transactions2.Count
    // transactions2 |> Seq.map(fun b -> b.Balance, b.Transaction.GetHash())
    // |> Seq.toArray
    // ``available coins`` |> List.map(fun v -> v.Amount) |> List.sum
    // ``available coins``
    // transactions2.Summary.Confirmed
    // Thomas: 50, John: 250+500+300+500

    ``save tracker`` @"c:\tracker.dat" tracker
    ``save chain`` @"c:\chain.dat" chain

    // let tracker2 = ``load tracker`` @"c:\tracker.dat"
    // let chain2 = ``load chain`` @"c:\chain.dat"

    // Some resources:
    // Article: https://www.codeproject.com/articles/835098/nbitcoin-build-them-all
    // A video: https://www.youtube.com/watch?v=_160oMzblY8
namespace System
namespace NBitcoin
namespace NBitcoin.Protocol
val network : Network

Full name: Script.network
val builder : NetworkBuilder
Multiple items
type NetworkBuilder =
  new : unit -> NetworkBuilder
  member AddAlias : alias:string -> NetworkBuilder
  member AddDNSSeeds : seeds:IEnumerable<DNSSeedData> -> NetworkBuilder
  member AddSeeds : seeds:IEnumerable<NetworkAddress> -> NetworkBuilder
  member BuildAndRegister : unit -> Network
  member CopyFrom : network:Network -> unit
  member SetBase58Bytes : type:Base58Type * bytes:byte[] -> NetworkBuilder
  member SetConsensus : consensus:Consensus -> NetworkBuilder
  member SetGenesis : genesis:Block -> NetworkBuilder
  member SetMagic : magic:uint32 -> NetworkBuilder
  ...

Full name: NBitcoin.NetworkBuilder

--------------------
NetworkBuilder() : unit
NetworkBuilder.CopyFrom(network: Network) : unit
type Network =
  val _MagicBytes : byte[]
  member AlertPubKey : PubKey
  member Consensus : Consensus
  member CreateAssetId : base58:string -> BitcoinAssetId
  member CreateBase58Data : type:Base58Type * base58:string -> Base58Data
  member CreateBitcoinAddress : base58:string -> BitcoinAddress + 1 overload
  member CreateBitcoinExtKey : key:ExtKey -> BitcoinExtKey + 1 overload
  member CreateBitcoinExtPubKey : pubkey:ExtPubKey -> BitcoinExtPubKey
  member CreateBitcoinScriptAddress : base58:string -> BitcoinScriptAddress
  member CreateBitcoinSecret : base58:string -> BitcoinSecret + 1 overload
  ...

Full name: NBitcoin.Network
property Network.Main: Network
val genesis : Block
Network.GetGenesis() : Block
NetworkBuilder.SetName(name: string) : NetworkBuilder
val getNewPrivateKey : unit -> byte []

Full name: Script.getNewPrivateKey


 Generate a new wallet private key for a new user as byte array
Multiple items
type Key =
  new : unit -> Key + 2 overloads
  member Derivate : cc:byte[] * nChild:uint32 * ccChild:byte[] -> Key
  member GetBitcoinSecret : network:Network -> BitcoinSecret
  member GetEncryptedBitcoinSecret : password:string * network:Network -> BitcoinEncryptedSecretNoEC
  member GetWif : network:Network -> BitcoinSecret
  member IsCompressed : bool with get, set
  member PubKey : PubKey
  member ReadWrite : stream:BitcoinStream -> unit
  member ScriptPubKey : Script
  member Sign : hash:uint256 -> ECDSASignature + 1 overload
  ...

Full name: NBitcoin.Key

--------------------
Key() : unit
Key(fCompressedIn: bool) : unit
Key(data: byte [], ?count: int, ?fCompressedIn: bool) : unit
val getSecret : bytes:byte [] -> BitcoinSecret

Full name: Script.getSecret


 Create BitcoinSecret from byte array
val bytes : byte []
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.byte

--------------------
type byte = Byte

Full name: Microsoft.FSharp.Core.byte
Multiple items
type BitcoinSecret =
  inherit Base58Data
  new : key:Key * network:Network -> BitcoinSecret + 1 overload
  member Copy : compressed:Nullable<bool> -> BitcoinSecret
  member Encrypt : password:string -> BitcoinEncryptedSecret
  member GetAddress : unit -> BitcoinPubKeyAddress
  member IsCompressed : bool
  member PrivateKey : Key
  member PubKey : PubKey
  member PubKeyHash : KeyId
  member ScriptPubKey : Script
  member Type : Base58Type

Full name: NBitcoin.BitcoinSecret

--------------------
BitcoinSecret(key: Key, network: Network) : unit
BitcoinSecret(base58: string, ?expectedAddress: Network) : unit
val leadingZeros : string

Full name: Script.leadingZeros


 Complexity of valid mining. Genesis is having 10.
 But this comes down to how much resources you are willing to
 spend to validate blockchain. Note: Some part of blockchain
 security comes from the fact that valid hashes are not so easy
 to calculate, making the generation of alternative valid blockchain slow.
type BlockChainCheck =
  | NoWork
  | EasyWork
  | CorrectWork

Full name: Script.BlockChainCheck


 Validation of blockchain hashes.
union case BlockChainCheck.NoWork: BlockChainCheck


 No validation
union case BlockChainCheck.EasyWork: BlockChainCheck


 Validation of leadingZeros amount only
union case BlockChainCheck.CorrectWork: BlockChainCheck


 Default Bitcoin level validation
Multiple items
type ChainedBlock =
  new : header:BlockHeader * height:int -> ChainedBlock + 1 overload
  member ChainWork : uint256
  member CheckProofOfWorkAndTarget : network:Network -> bool + 1 overload
  member EnumerateToGenesis : unit -> IEnumerable<ChainedBlock>
  member Equals : obj:obj -> bool
  member FindAncestorOrSelf : height:int -> ChainedBlock + 1 overload
  member FindFork : block:ChainedBlock -> ChainedBlock
  member GetAncestor : height:int -> ChainedBlock
  member GetHashCode : unit -> int
  member GetLocator : unit -> BlockLocator
  ...

Full name: NBitcoin.ChainedBlock

--------------------
ChainedBlock(header: BlockHeader, height: int) : unit
ChainedBlock(header: BlockHeader, headerHash: uint256, previous: ChainedBlock) : unit
val cb : ChainedBlock
member ChainedBlock.ValidateEasy : network:Network -> bool

Full name: Script.ValidateEasy


 Re-implementation of Validate()
val network : Network
val genesis : bool
property ChainedBlock.Height: int
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
property ChainedBlock.Previous: ChainedBlock
val heightCorrect : bool
val genesisCorrect : bool
property ChainedBlock.HashBlock: uint256
val hashPrevCorrect : bool
property ChainedBlock.Header: BlockHeader
property BlockHeader.HashPrevBlock: uint256
val hashCorrect : bool
BlockHeader.GetHash() : uint256
val workCorrect : bool
type ChainBase =
  member Contains : hash:uint256 -> bool + 1 overload
  member EnumerateAfter : blockHash:uint256 -> IEnumerable<ChainedBlock> + 1 overload
  member EnumerateToTip : block:ChainedBlock -> IEnumerable<ChainedBlock> + 1 overload
  member FindFork : chain:ChainBase -> ChainedBlock + 2 overloads
  member Genesis : ChainedBlock
  member GetBlock : id:uint256 -> ChainedBlock + 1 overload
  member GetWorkRequired : network:Network * height:int -> Target
  member Height : int
  member SameTip : chain:ChainBase -> bool
  member SetTip : otherChain:ChainBase -> ChainedBlock + 2 overloads
  ...

Full name: NBitcoin.ChainBase
val cb : ChainBase
member ChainBase.ValidateEasy : network:Network * ?fullChain:bool -> bool

Full name: Script.ValidateEasy


 Re-implementation of Validate()
val fullChain : bool option
val tip : ChainedBlock
property ChainBase.Tip: ChainedBlock
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val anyFails : bool
ChainedBlock.EnumerateToGenesis() : Collections.Generic.IEnumerable<ChainedBlock>
module Seq

from Microsoft.FSharp.Collections
val exists : predicate:('T -> bool) -> source:seq<'T> -> bool

Full name: Microsoft.FSharp.Collections.Seq.exists
val block : ChainedBlock
member ChainedBlock.ValidateEasy : network:Network -> bool


 Re-implementation of Validate()
val ( mine to correct ) : checkType:BlockChainCheck -> chain:ConcurrentChain -> block:Block -> unit

Full name: Script.( mine to correct )


 This will mine the correct hash.
 Performance is not optimized: if you would really want to do
 mining, you would probably want to use some more parallel algorithm.
val checkType : BlockChainCheck
val chain : ConcurrentChain
Multiple items
type ConcurrentChain =
  inherit ChainBase
  new : unit -> ConcurrentChain + 3 overloads
  member Clone : unit -> ConcurrentChain
  member GetBlock : id:uint256 -> ChainedBlock + 1 overload
  member Height : int
  member Load : chain:byte[] -> unit + 2 overloads
  member SetTip : block:ChainedBlock -> ChainedBlock
  member Tip : ChainedBlock
  member ToBytes : unit -> byte[]
  member ToString : unit -> string
  member WriteTo : stream:Stream -> unit + 1 overload

Full name: NBitcoin.ConcurrentChain

--------------------
ConcurrentChain() : unit
ConcurrentChain(genesis: BlockHeader) : unit
ConcurrentChain(network: Network) : unit
ConcurrentChain(bytes: byte []) : unit
val block : Block
Multiple items
type Block =
  new : unit -> Block + 2 overloads
  member AddTransaction : tx:Transaction -> Transaction
  member Check : unit -> bool
  member CheckMerkleRoot : unit -> bool
  member CheckProofOfWork : unit -> bool
  member CreateNextBlockWithCoinbase : address:BitcoinAddress * height:int -> Block + 3 overloads
  member Filter : [<ParamArray>] txIds:uint256[] -> MerkleBlock + 1 overload
  member GetHash : unit -> uint256
  member GetMerkleRoot : unit -> MerkleNode
  member Header : BlockHeader
  ...

Full name: NBitcoin.Block

--------------------
Block() : unit
Block(blockHeader: BlockHeader) : unit
Block(bytes: byte []) : unit
val validation : (ChainedBlock -> bool)
ChainedBlock.Validate(network: Network) : bool
val mine : (uint32 -> unit)
val nonce : uint32
property Block.Header: BlockHeader
property BlockHeader.Nonce: uint32
val headerBlock : ChainedBlock
ConcurrentChain.GetBlock(height: int) : ChainedBlock
ConcurrentChain.GetBlock(id: uint256) : ChainedBlock
val ( attach to chain ) : checkType:BlockChainCheck -> chain:ConcurrentChain -> block:Block -> ChainedBlock

Full name: Script.( attach to chain )


 Attach a block to chain
val header : BlockHeader
property ConcurrentChain.Tip: ChainedBlock
property BlockHeader.Bits: Target
ChainedBlock.GetWorkRequired(consensus: Consensus) : Target
ChainedBlock.GetWorkRequired(network: Network) : Target
property BlockHeader.BlockTime: DateTimeOffset
Multiple items
type DateTimeOffset =
  struct
    new : dateTime:DateTime -> DateTimeOffset + 5 overloads
    member Add : timeSpan:TimeSpan -> DateTimeOffset
    member AddDays : days:float -> DateTimeOffset
    member AddHours : hours:float -> DateTimeOffset
    member AddMilliseconds : milliseconds:float -> DateTimeOffset
    member AddMinutes : minutes:float -> DateTimeOffset
    member AddMonths : months:int -> DateTimeOffset
    member AddSeconds : seconds:float -> DateTimeOffset
    member AddTicks : ticks:int64 -> DateTimeOffset
    member AddYears : years:int -> DateTimeOffset
    ...
  end

Full name: System.DateTimeOffset

--------------------
DateTimeOffset()
DateTimeOffset(dateTime: DateTime) : unit
DateTimeOffset(ticks: int64, offset: TimeSpan) : unit
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : unit
property DateTimeOffset.UtcNow: DateTimeOffset
Multiple items
type RandomUtils =
  new : unit -> RandomUtils
  static member AddEntropy : data:string -> unit + 1 overload
  static member GetBytes : length:int -> byte[] + 1 overload
  static member GetInt32 : unit -> int
  static member GetInt64 : unit -> int64
  static member GetUInt32 : unit -> uint32
  static member GetUInt64 : unit -> uint64
  static member Random : IRandom with get, set

Full name: NBitcoin.RandomUtils

--------------------
RandomUtils() : unit
RandomUtils.GetUInt32() : uint32
Block.UpdateMerkleRoot() : unit
ChainBase.SetTip(header: BlockHeader) : bool
ChainBase.SetTip(otherChain: ChainBase) : ChainedBlock
ConcurrentChain.SetTip(block: ChainedBlock) : ChainedBlock
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val ( to new block ) : txs:seq<#Transaction> -> Block

Full name: Script.( to new block )


 Attach a bunch of transactions to a new block
val txs : seq<#Transaction>
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
Block.AddTransaction(tx: Transaction) : Transaction
val noFees : FeeRate

Full name: Script.noFees


 No fees on our custom block-chain
 Consifer adding some fee when you want users to do the mining.
module Unchecked

from Microsoft.FSharp.Core.Operators
val defaultof<'T> : 'T

Full name: Microsoft.FSharp.Core.Operators.Unchecked.defaultof
Multiple items
type FeeRate =
  new : feePerK:Money -> FeeRate + 1 overload
  member CompareTo : other:FeeRate -> int + 1 overload
  member Equals : obj:obj -> bool + 1 overload
  member FeePerK : Money
  member GetFee : size:int -> Money + 1 overload
  member GetHashCode : unit -> int
  member ToString : unit -> string
  static member Max : left:FeeRate * right:FeeRate -> FeeRate
  static member Min : left:FeeRate * right:FeeRate -> FeeRate
  static member Zero : FeeRate

Full name: NBitcoin.FeeRate

--------------------
FeeRate(feePerK: Money) : unit
FeeRate(feePaid: Money, size: int) : unit
val txBuilder : unit -> TransactionBuilder

Full name: Script.txBuilder
val b : TransactionBuilder
Multiple items
type TransactionBuilder =
  new : unit -> TransactionBuilder + 1 overload
  member AddCoins : [<ParamArray>] coins:ICoin[] -> TransactionBuilder + 2 overloads
  member AddKeys : [<ParamArray>] keys:ISecret[] -> TransactionBuilder + 1 overload
  member AddKnownRedeems : [<ParamArray>] knownRedeems:Script[] -> TransactionBuilder
  member AddKnownSignature : pubKey:PubKey * signature:TransactionSignature -> TransactionBuilder + 1 overload
  member BuildTransaction : sign:bool -> Transaction + 1 overload
  member Check : tx:Transaction -> TransactionPolicyError[] + 2 overloads
  member CoinFinder : Func<OutPoint, ICoin> with get, set
  member CoinSelector : ICoinSelector with get, set
  member CombineSignatures : [<ParamArray>] transactions:Transaction[] -> Transaction
  ...

Full name: NBitcoin.TransactionBuilder

--------------------
TransactionBuilder() : unit
TransactionBuilder(seed: int) : unit
property TransactionBuilder.StandardTransactionPolicy: Policy.StandardTransactionPolicy
property Policy.StandardTransactionPolicy.MinRelayTxFee: FeeRate
property FeeRate.Zero: FeeRate
val ( give money ) : toUser:BitcoinSecret -> sum:int -> Transaction

Full name: Script.( give money )


 Coinbase transaction is a transaction to generate money to our system.
val toUser : BitcoinSecret
val sum : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val money : Money
Multiple items
type Money =
  new : satoshis:int -> Money + 4 overloads
  member Abs : unit -> Money
  member Almost : amount:Money * dust:Money -> bool + 1 overload
  member CompareTo : other:Money -> int + 1 overload
  member Equals : other:Money -> bool + 1 overload
  member GetHashCode : unit -> int
  member Satoshi : int64 with get, set
  member Split : parts:int -> IEnumerable<Money>
  member ToDecimal : unit:MoneyUnit -> decimal
  member ToString : unit -> string + 1 overload
  ...

Full name: NBitcoin.Money

--------------------
Money(satoshis: int) : unit
Money(satoshis: uint32) : unit
Money(satoshis: int64) : unit
Money(satoshis: uint64) : unit
Money(amount: decimal, unit: MoneyUnit) : unit
val coin : Coin
Multiple items
type Coin =
  new : unit -> Coin + 5 overloads
  member Amount : Money with get, set
  member CanGetScriptCode : bool
  member GetHashVersion : unit -> HashVersion
  member GetScriptCode : unit -> Script
  member Outpoint : OutPoint with get, set
  member ScriptPubKey : Script with get, set
  member ToColoredCoin : asset:AssetMoney -> ColoredCoin + 2 overloads
  member ToScriptCoin : redeemScript:Script -> ScriptCoin
  member TxOut : TxOut with get, set

Full name: NBitcoin.Coin

--------------------
Coin() : unit
Coin(txOut: IndexedTxOut) : unit
Coin(fromOutpoint: OutPoint, fromTxOut: TxOut) : unit
Coin(fromTx: Transaction, fromOutputIndex: uint32) : unit
Coin(fromTx: Transaction, fromOutput: TxOut) : unit
Coin(fromTxHash: uint256, fromOutputIndex: uint32, amount: Money, scriptPubKey: Script) : unit
Multiple items
type OutPoint =
  new : unit -> OutPoint + 5 overloads
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member Hash : uint256 with get, set
  member IsNull : bool
  member N : uint32 with get, set
  member ReadWrite : stream:BitcoinStream -> unit
  member ToString : unit -> string
  static member Parse : str:string -> OutPoint
  static member TryParse : str:string * result:OutPoint -> bool

Full name: NBitcoin.OutPoint

--------------------
OutPoint() : unit
OutPoint(outpoint: OutPoint) : unit
OutPoint(hashIn: uint256, nIn: uint32) : unit
OutPoint(hashIn: uint256, nIn: int) : unit
OutPoint(tx: Transaction, i: uint32) : unit
OutPoint(tx: Transaction, i: int) : unit
Multiple items
type TxOut =
  new : unit -> TxOut + 2 overloads
  member GetDustThreshold : minRelayTxFee:FeeRate -> Money
  member IsDust : minRelayTxFee:FeeRate -> bool
  member IsTo : destination:IDestination -> bool
  member ReadWrite : stream:BitcoinStream -> unit
  member ScriptPubKey : Script with get, set
  member Value : Money with get, set
  static member Parse : hex:string -> TxOut

Full name: NBitcoin.TxOut

--------------------
TxOut() : unit
TxOut(value: Money, destination: IDestination) : unit
TxOut(value: Money, scriptPubKey: Script) : unit
property BitcoinSecret.PubKey: PubKey
property PubKey.ScriptPubKey: Script
val builder : TransactionBuilder
val tx : Transaction
type ICoin =
  member Amount : IMoney
  member CanGetScriptCode : bool
  member GetHashVersion : unit -> HashVersion
  member GetScriptCode : unit -> Script
  member Outpoint : OutPoint
  member TxOut : TxOut

Full name: NBitcoin.ICoin
BitcoinSecret.GetAddress() : BitcoinPubKeyAddress
property Transaction.IsCoinBase: bool
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val ok : bool
val errs : Policy.TransactionPolicyError []
TransactionBuilder.Verify(tx: Transaction) : bool
TransactionBuilder.Verify(tx: Transaction, errors: byref<Policy.TransactionPolicyError []>) : bool
TransactionBuilder.Verify(tx: Transaction, expectedFeeRate: FeeRate) : bool
TransactionBuilder.Verify(tx: Transaction, expectedFees: Money) : bool
TransactionBuilder.Verify(tx: Transaction, expectedFeeRate: FeeRate, errors: byref<Policy.TransactionPolicyError []>) : bool
TransactionBuilder.Verify(tx: Transaction, expectedFees: Money, errors: byref<Policy.TransactionPolicyError []>) : bool
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
String.Join(separator: string, values: Collections.Generic.IEnumerable<string>) : string
String.Join<'T>(separator: string, values: Collections.Generic.IEnumerable<'T>) : string
String.Join(separator: string, [<ParamArray>] values: obj []) : string
String.Join(separator: string, [<ParamArray>] value: string []) : string
String.Join(separator: string, value: string [], startIndex: int, count: int) : string
val ( spend money ) : coins:Coin list -> fromUser:BitcoinSecret -> toUser:BitcoinPubKeyAddress -> sum:int -> Transaction

Full name: Script.( spend money )


 Normal transaction to transfer money / asset from user to next user.
 Needs outpoint from previous transaction to make a block chain.
val coins : Coin list
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val fromUser : BitcoinSecret
val toUser : BitcoinPubKeyAddress
Multiple items
type BitcoinPubKeyAddress =
  inherit BitcoinAddress
  new : base58:string * ?expectedNetwork:Network -> BitcoinPubKeyAddress + 1 overload
  member Hash : KeyId
  member Type : Base58Type
  member VerifyMessage : message:string * signature:string -> bool

Full name: NBitcoin.BitcoinPubKeyAddress

--------------------
BitcoinPubKeyAddress(base58: string, ?expectedNetwork: Network) : unit
BitcoinPubKeyAddress(keyId: KeyId, network: Network) : unit
val fees : Money
property Money.Zero: Money
val coinsArr : ICoin []
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val c : Coin
property Coin.TxOut: TxOut
TxOut.IsTo(destination: IDestination) : bool
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val toArray : list:'T list -> 'T []

Full name: Microsoft.FSharp.Collections.List.toArray
val makeUser : unit -> BitcoinSecret

Full name: Script.makeUser


 Create a new user
val user : BitcoinSecret
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.WriteLine() : unit
   (+0 other overloads)
Console.WriteLine(value: string) : unit
   (+0 other overloads)
Console.WriteLine(value: obj) : unit
   (+0 other overloads)
Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
Console.WriteLine(value: int64) : unit
   (+0 other overloads)
Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
Console.WriteLine(value: int) : unit
   (+0 other overloads)
Console.WriteLine(value: float32) : unit
   (+0 other overloads)
Console.WriteLine(value: float) : unit
   (+0 other overloads)
Console.WriteLine(value: decimal) : unit
   (+0 other overloads)
property BitcoinSecret.PrivateKey: Key
Key.GetWif(network: Network) : BitcoinSecret
val ( fetch coins of ) : dest:IDestination -> tx:Transaction -> Coin list

Full name: Script.( fetch coins of )


 Get coins from transaction
val dest : IDestination
Multiple items
type Transaction =
  new : unit -> Transaction + 2 overloads
  member AddInput : in:TxIn -> TxIn + 1 overload
  member AddOutput : out:TxOut -> TxOut + 2 overloads
  member CacheHashes : unit -> unit
  member CalculateSequenceLocks : prevHeights:int[] * block:ChainedBlock * ?flags:LockTimeFlags -> SequenceLock
  member Check : unit -> TransactionCheckResult
  member CheckSequenceLocks : prevHeights:int[] * block:ChainedBlock * ?flags:LockTimeFlags -> bool
  member Clone : cloneCache:bool -> Transaction
  member CreatePayload : unit -> TxPayload
  member GetFee : spentCoins:ICoin[] -> Money
  ...
  nested type LockTimeFlags

Full name: NBitcoin.Transaction

--------------------
Transaction() : unit
Transaction(bytes: byte []) : unit
Transaction(hex: string, ?version: ProtocolVersion) : unit
property Transaction.Outputs: TxOutList
val mapi : mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.mapi
val idx : int
val op : TxOut
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
property TxOut.Value: Money
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val toList : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.Seq.toList
val ( save tracker ) : filename:string -> tracker:SPV.Tracker -> unit

Full name: Script.( save tracker )
val filename : string
val tracker : SPV.Tracker
namespace NBitcoin.SPV
Multiple items
type Tracker =
  new : unit -> Tracker
  member Add : destination:IDestination * ?isRedeemScript:bool * ?isInternal:bool * ?filter:string * ?wallet:string -> unit + 1 overload
  member CreateBloomFilter : fp:float * ?flags:BloomFlags -> BloomFilter
  member GetDataToTrack : ?filter:string -> IEnumerable<byte[]>
  member GetKnownTransaction : txId:uint256 -> Transaction
  member GetWalletTransactions : chain:ChainBase * ?wallet:string -> WalletTransactionsCollection
  member NotifyTransaction : transaction:Transaction -> bool + 2 overloads
  member Save : stream:Stream -> unit
  member UpdateTweak : unit -> unit
  member Validate : unit -> bool
  ...
  nested type IOperation
  nested type NewTrackerOperation

Full name: NBitcoin.SPV.Tracker

--------------------
SPV.Tracker() : unit
val filterBefore : BloomFilter
SPV.Tracker.CreateBloomFilter(fp: float, ?flags: BloomFlags) : BloomFilter
val fileStream : IO.FileStream
namespace System.IO
type File =
  static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
  static member AppendAllText : path:string * contents:string -> unit + 1 overload
  static member AppendText : path:string -> StreamWriter
  static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
  static member Create : path:string -> FileStream + 3 overloads
  static member CreateText : path:string -> StreamWriter
  static member Decrypt : path:string -> unit
  static member Delete : path:string -> unit
  static member Encrypt : path:string -> unit
  static member Exists : path:string -> bool
  ...

Full name: System.IO.File
IO.File.Create(path: string) : IO.FileStream
IO.File.Create(path: string, bufferSize: int) : IO.FileStream
IO.File.Create(path: string, bufferSize: int, options: IO.FileOptions) : IO.FileStream
IO.File.Create(path: string, bufferSize: int, options: IO.FileOptions, fileSecurity: Security.AccessControl.FileSecurity) : IO.FileStream
SPV.Tracker.Save(stream: IO.Stream) : unit
val ( load tracker ) : filename:string -> SPV.Tracker

Full name: Script.( load tracker )
IO.File.OpenRead(path: string) : IO.FileStream
SPV.Tracker.Load(stream: IO.Stream) : SPV.Tracker
SPV.Tracker.Validate() : bool
val ( save chain ) : filename:string -> chain:ConcurrentChain -> unit

Full name: Script.( save chain )
ConcurrentChain.WriteTo(stream: BitcoinStream) : unit
ConcurrentChain.WriteTo(stream: IO.Stream) : unit
Multiple items
type BitcoinStream =
  new : bytes:byte[] -> BitcoinStream + 1 overload
  member BigEndianScope : unit -> IDisposable
  member CopyParameters : stream:BitcoinStream -> unit
  member Counter : PerformanceCounter
  member Inner : Stream
  member IsBigEndian : bool with get, set
  member MaxArraySize : int with get, set
  member ProtocolVersion : ProtocolVersion with get, set
  member ProtocolVersionScope : version:ProtocolVersion -> IDisposable
  member ReadCancellationToken : CancellationToken with get, set
  ...

Full name: NBitcoin.BitcoinStream

--------------------
BitcoinStream(bytes: byte []) : unit
BitcoinStream(inner: IO.Stream, serializing: bool) : unit
val ( load chain ) : filename:string -> ConcurrentChain

Full name: Script.( load chain )
IO.File.ReadAllBytes(path: string) : byte []
ConcurrentChain.Load(stream: BitcoinStream) : unit
ConcurrentChain.Load(stream: IO.Stream) : unit
ConcurrentChain.Load(chain: byte []) : unit
member ChainBase.ValidateEasy : network:Network * ?fullChain:bool -> bool


 Re-implementation of Validate()
val testing : unit -> unit

Full name: Script.testing
val thomas : BitcoinSecret
val antero : BitcoinSecret
val john : BitcoinSecret
SPV.Tracker.Add(scriptPubKey: Script, ?isRedeemScript: bool, ?isInternal: bool, ?filter: string, ?wallet: string) : bool
SPV.Tracker.Add(destination: IDestination, ?isRedeemScript: bool, ?isInternal: bool, ?filter: string, ?wallet: string) : unit
val coinbase1 : Transaction
val coins1 : Coin list
val transfer1 : Transaction
val coins2 : Coin list
val transfer2 : Transaction
val block1 : Block
val chained1 : ChainedBlock
property Block.Transactions: Collections.Generic.List<Transaction>
SPV.Tracker.NotifyTransaction(transaction: Transaction) : bool
SPV.Tracker.NotifyTransaction(transaction: Transaction, chainedBlock: ChainedBlock, proof: MerkleBlock) : bool
SPV.Tracker.NotifyTransaction(transaction: Transaction, chainedBlock: ChainedBlock, block: Block) : bool
val ( chain ok ) : bool
val ( tracker ok ) : bool
val transactions1 : SPV.WalletTransactionsCollection
SPV.Tracker.GetWalletTransactions(chain: ChainBase, ?wallet: string) : SPV.WalletTransactionsCollection
val coinbase2 : Transaction
val coins3 : Coin list
val transfer3 : Transaction
val coins4 : Coin list
val transfer4 : Transaction
val block2 : Block
val chained2 : ChainedBlock
val ( chain still ok ) : bool
val ( tracker still ok ) : bool
val transactions2 : SPV.WalletTransactionsCollection
val ( available coins ) : Coin list
SPV.WalletTransactionsCollection.GetSpendableCoins() : Collections.Generic.IEnumerable<Coin>
Next Version Raw view Test code New version

More information

Link:http://fssnip.net/7RY
Posted:7 years ago
Author:Tuomas Hietanen
Tags: blockchain , btc