# encoding: ascii-8bit module Bitcoin module Protocol class Block BLOCK_VERSION_DEFAULT = (1 << 0) BLOCK_VERSION_AUXPOW = (1 << 8) BLOCK_VERSION_CHAIN_START = (1 << 16) BLOCK_VERSION_CHAIN_END = (1 << 30) # block hash attr_accessor :hash # previous block hash attr_accessor :prev_block # transactions (Array of Tx) attr_accessor :tx # merkle root attr_accessor :mrkl_root # block generation time attr_accessor :time # difficulty target bits attr_accessor :bits # nonce (number counted when searching for block hash matching target) attr_accessor :nonce # version (usually 1) attr_accessor :ver # raw protocol payload attr_accessor :payload # AuxPow linking the block to a merge-mined chain attr_accessor :aux_pow alias :transactions :tx # compare to another block def ==(other) @hash == other.hash end def binary_hash [@hash].pack("H*") end def prev_block_hex @prev_block_hex ||= @prev_block.reverse.unpack("H*")[0] end # create block from raw binary +data+ def initialize(data) @tx = [] parse_data_from_io(data) if data end # parse raw binary data def parse_data(data) buf = parse_data_from_io(data) buf.eof? ? true : buf.read end # parse raw binary data def parse_data_from_io(buf, header_only=false) buf = buf.is_a?(String) ? StringIO.new(buf) : buf @ver, @prev_block, @mrkl_root, @time, @bits, @nonce = buf.read(80).unpack("Va32a32VVV") recalc_block_hash if (@ver & BLOCK_VERSION_AUXPOW) > 0 @aux_pow = AuxPow.new(nil) @aux_pow.parse_data_from_io(buf) end return buf if buf.eof? tx_size = Protocol.unpack_var_int_from_io(buf) @tx_count = tx_size return buf if header_only tx_size.times{ break if payload == true t = Tx.new(nil) payload = t.parse_data_from_io(buf) @tx << t } @payload = to_payload buf end # recalculate the block hash def recalc_block_hash @hash = Bitcoin.block_hash(@prev_block.reverse_hth, @mrkl_root.reverse_hth, @time, @bits, @nonce, @ver) end def recalc_mrkl_root @mrkl_root = Bitcoin.hash_mrkl_tree( @tx.map(&:hash) ).last.htb_reverse end # verify mrkl tree def verify_mrkl_root @mrkl_root.reverse_hth == Bitcoin.hash_mrkl_tree( @tx.map(&:hash) ).last end # get the block header info # [, , ,