class MerkleTree
Constants
- MAJOR
- MINOR
- PATCH
- VERSION
Attributes
leaves[R]
root[R]
Public Class Methods
calc_hash( data )
click to toggle source
# File lib/merkletree.rb, line 163 def self.calc_hash( data ) sha = Digest::SHA256.new sha.update( data ) sha.hexdigest end
compute_root( *args )
click to toggle source
shortcut/convenience - compute root hash w/o building tree nodes
# File lib/merkletree.rb, line 128 def self.compute_root( *args ) if args.size == 1 && args[0].is_a?( Array ) hashes = args[0] ## "unwrap" array in array else hashes = args ## use "auto-wrapped" splat array end ## todo/fix: handle hashes.size == 0 case ## - throw exception - why? why not? ## - return empty node with hash '0' - why? why not? if hashes.size == 1 hashes[0] else ## while there's more than one hash in the list, keep looping... while hashes.size > 1 # if number of hashes is odd e.g. 3,5,7,etc., duplicate last hash in list hashes << hashes[-1] if hashes.size % 2 != 0 ## loop through hashes two at a time hashes = hashes.each_slice(2).map do |left,right| ## join both hashes slice[0]+slice[1] together hash = calc_hash( left + right ) end end ## debug output ## puts "current merkle hashes (#{hashes.size}):" ## pp hashes ### finally we end up with a single hash hashes[0] end end
compute_root_for( *args )
click to toggle source
# File lib/merkletree.rb, line 64 def self.compute_root_for( *args ) 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 ## for now use to_s for calculation hash hashes = transactions.map { |tx| calc_hash( tx.to_s ) } self.compute_root( hashes ) end
for( *args )
click to toggle source
convenience helpers
# File lib/merkletree.rb, line 53 def self.for( *args ) 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 ## for now use to_s for calculation hash hashes = transactions.map { |tx| calc_hash( tx.to_s ) } self.new( hashes ) end
new( *args )
click to toggle source
# File lib/merkletree.rb, line 81 def initialize( *args ) if args.size == 1 && args[0].is_a?( Array ) hashes = args[0] ## "unwrap" array in array else hashes = args ## use "auto-wrapped" splat array end @hashes = hashes @root = build_tree end
root()
click to toggle source
# File lib/merkletree/version.rb, line 18 def self.root File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) ) end
version()
click to toggle source
# File lib/merkletree/version.rb, line 10 def self.version VERSION end
Public Instance Methods
build_tree()
click to toggle source
# File lib/merkletree.rb, line 93 def build_tree level = @leaves = @hashes.map { |hash| Node.new( hash, nil, nil ) } ## todo/fix: handle hashes.size == 0 case ## - throw exception - why? why not? ## - return empty node with hash '0' - why? why not? if @hashes.size == 1 level[0] else ## while there's more than one hash in the layer, keep looping... while level.size > 1 ## loop through hashes two at a time level = level.each_slice(2).map do |left, right| ## note: handle special case # if number of nodes is odd e.g. 3,5,7,etc. # last right node is nil -- duplicate node value for hash ## todo/check - duplicate just hash? or add right node ref too - why? why not? right = left if right.nil? Node.new( MerkleTree.calc_hash( left.value + right.value ), left, right) end ## debug output ## puts "current merkle hash level (#{level.size} nodes):" ## pp level end ### finally we end up with a single hash level[0] end end