class BlockchainLite::ProofOfWork::Block

Attributes

hash[R]
index[R]
nonce[R]
previous_hash[R]
timestamp[R]
transactions[R]
transactions_count[R]
transactions_hash[R]

Public Class Methods

first( *args, **opts ) click to toggle source
# File lib/blockchain-lite/proof_of_work/block.rb, line 48
def self.first( *args, **opts )    # create genesis (big bang! first) block
  ##  note: allow/support splat-* for now for convenience (auto-wraps args into array)
  if args.size == 1 && args[0].is_a?( Array )
    transactions = args[0]   ## "unwrap" array in array
  else
    transactions = args      ## use "auto-wrapped" splat array
  end
  ## uses index zero (0) and arbitrary previous_hash ('0')
  ##  note: pass along (optional) custom timestamp (e.g. used for 1637 etc.)
  Block.new( 0, transactions, '0', timestamp: opts[:timestamp] )
end
new(index, transactions, previous_hash, timestamp: nil, nonce: nil) click to toggle source
# File lib/blockchain-lite/proof_of_work/block.rb, line 18
def initialize(index, transactions, previous_hash, timestamp: nil, nonce: nil)
  @index = index

  ## note: assumes / expects an array for transactions
  @transactions       = transactions
  @transactions_count = transactions.size

  ## todo: add empty array check to merkletree.compute why? why not?
  @transactions_hash  = transactions.empty? ? '0' : MerkleTree.compute_root_for( transactions )

  @previous_hash = previous_hash

  ## note: use coordinated universal time (utc)
  @timestamp = timestamp ? timestamp : Time.now.utc

  if nonce     ## restore pre-computed/mined block (from disk/cache/db/etc.)
     ## todo: check timestamp MUST NOT be nil
     @nonce = nonce
     @hash  = calc_hash
  else   ## new block  (mine! e.g. find nonce - "lucky" number used once)
     @nonce, @hash = compute_hash_with_proof_of_work
  end
end
next( previous, *args, **opts ) click to toggle source
# File lib/blockchain-lite/proof_of_work/block.rb, line 60
def self.next( previous, *args, **opts )
  ## note: allow/support splat-* for now for convenience (auto-wraps args into array)
  if args.size == 1 && args[0].is_a?( Array )
    transactions = args[0]   ## "unwrap" array in array
  else
    transactions = args      ## use "auto-wrapped" splat array
  end
  Block.new( previous.index+1, transactions, previous.hash, timestamp: opts[:timestamp] )
end

Public Instance Methods

calc_hash() click to toggle source
# File lib/blockchain-lite/proof_of_work/block.rb, line 42
def calc_hash
  calc_hash_with_nonce( @nonce )
end

Private Instance Methods

calc_hash_with_nonce( nonce=0 ) click to toggle source
# File lib/blockchain-lite/proof_of_work/block.rb, line 72
def calc_hash_with_nonce( nonce=0 )
  sha = Digest::SHA256.new
  sha.update( nonce.to_s +
              @timestamp.to_s +
              @transactions_hash +
              @previous_hash )
  sha.hexdigest
end
compute_hash_with_proof_of_work( difficulty='00' ) click to toggle source
# File lib/blockchain-lite/proof_of_work/block.rb, line 81
def compute_hash_with_proof_of_work( difficulty='00' )
  nonce = 0
  loop do
    hash = calc_hash_with_nonce( nonce )
    if hash.start_with?( difficulty )
      return [nonce,hash]    ## bingo! proof of work if hash starts with leading zeros (00)
    else
      nonce += 1             ## keep trying (and trying and trying)
    end
  end
end