Class: Bitcoin::Protocol::Block
- Inherits:
-
Object
- Object
- Bitcoin::Protocol::Block
- Defined in:
- lib/bitcoin/protocol/block.rb
Constant Summary collapse
- BLOCK_VERSION_DEFAULT =
(1 << 0)
- BLOCK_VERSION_AUXPOW =
(1 << 8)
- BLOCK_VERSION_CHAIN_START =
(1 << 16)
- BLOCK_VERSION_CHAIN_END =
(1 << 30)
Instance Attribute Summary collapse
-
#aux_pow ⇒ Object
AuxPow linking the block to a merge-mined chain.
-
#bits ⇒ Object
difficulty target bits.
-
#hash ⇒ Object
block hash.
-
#mrkl_root ⇒ Object
merkle root.
-
#nonce ⇒ Object
nonce (number counted when searching for block hash matching target).
-
#partial_merkle_tree ⇒ Object
readonly
Returns the value of attribute partial_merkle_tree.
-
#payload ⇒ Object
raw protocol payload.
-
#prev_block_hash ⇒ Object
(also: #prev_block)
previous block hash.
-
#time ⇒ Object
block generation time.
-
#tx ⇒ Object
(also: #transactions)
transactions (Array of Tx).
-
#ver ⇒ Object
version (usually 1).
Class Method Summary collapse
-
.binary_from_hash(h) ⇒ Object
convert ruby hash to raw binary.
-
.binary_from_json(json_string) ⇒ Object
convert json representation to raw binary.
-
.from_file(path) ⇒ Object
read binary block from a file.
-
.from_hash(h, do_raise = true) ⇒ Object
parse ruby hash (see also #to_hash).
-
.from_json(json_string) ⇒ Object
parse json representation (see also #to_json).
-
.from_json_file(path) ⇒ Object
read json block from a file.
Instance Method Summary collapse
-
#==(other) ⇒ Object
compare to another block.
- #binary_hash ⇒ Object
-
#bip34_block_height(height = nil) ⇒ Object
introduced in block version 2 by BIP_0034 blockchain height as seen by the block itself.
-
#block_header ⇒ Object
block header binary output.
-
#block_work ⇒ Object
get the (statistical) amount of work that was needed to generate this block.
- #decimaltarget ⇒ Object
- #difficulty ⇒ Object
-
#header_info ⇒ Object
get the block header info [<version>, <prev_block>, <merkle_root>, <time>, <bits>, <nonce>, <txcount>, <size>].
-
#header_to_json(options = {:space => ''}) ⇒ Object
convert header to json representation.
- #hextarget ⇒ Object
-
#initialize(data = nil) ⇒ Block
constructor
create block from raw binary
data
. -
#parse_data(data) ⇒ Object
parse raw binary data.
-
#parse_data_from_io(buf, header_only = false) ⇒ Object
parse raw binary data.
- #prev_block=(hash) ⇒ Object
- #prev_block_hex ⇒ Object
-
#recalc_block_hash ⇒ Object
recalculate the block hash.
- #recalc_block_scrypt_hash ⇒ Object
- #recalc_mrkl_root ⇒ Object
- #size ⇒ Object
-
#to_hash(options = {}) ⇒ Object
convert to ruby hash (see also #from_hash).
-
#to_json(options = {:space => ''}, *a) ⇒ Object
convert to json representation as seen in the block explorer.
-
#to_json_file(path) ⇒ Object
write json representation to a file (see also #to_json).
-
#to_payload ⇒ Object
convert to raw binary format.
- #tx_hashes ⇒ Object
-
#verify_mrkl_root ⇒ Object
verify mrkl tree.
Constructor Details
#initialize(data = nil) ⇒ Block
create block from raw binary data
63 64 65 66 |
# File 'lib/bitcoin/protocol/block.rb', line 63 def initialize(data=nil) @tx = [] parse_data_from_io(data) if data end |
Instance Attribute Details
#aux_pow ⇒ Object
AuxPow linking the block to a merge-mined chain
43 44 45 |
# File 'lib/bitcoin/protocol/block.rb', line 43 def aux_pow @aux_pow end |
#bits ⇒ Object
difficulty target bits
31 32 33 |
# File 'lib/bitcoin/protocol/block.rb', line 31 def bits @bits end |
#hash ⇒ Object
block hash
14 15 16 |
# File 'lib/bitcoin/protocol/block.rb', line 14 def hash @hash end |
#mrkl_root ⇒ Object
merkle root
25 26 27 |
# File 'lib/bitcoin/protocol/block.rb', line 25 def mrkl_root @mrkl_root end |
#nonce ⇒ Object
nonce (number counted when searching for block hash matching target)
34 35 36 |
# File 'lib/bitcoin/protocol/block.rb', line 34 def nonce @nonce end |
#partial_merkle_tree ⇒ Object (readonly)
Returns the value of attribute partial_merkle_tree.
45 46 47 |
# File 'lib/bitcoin/protocol/block.rb', line 45 def partial_merkle_tree @partial_merkle_tree end |
#payload ⇒ Object
raw protocol payload
40 41 42 |
# File 'lib/bitcoin/protocol/block.rb', line 40 def payload @payload end |
#prev_block_hash ⇒ Object Also known as: prev_block
previous block hash
17 18 19 |
# File 'lib/bitcoin/protocol/block.rb', line 17 def prev_block_hash @prev_block_hash end |
#time ⇒ Object
block generation time
28 29 30 |
# File 'lib/bitcoin/protocol/block.rb', line 28 def time @time end |
#tx ⇒ Object Also known as: transactions
transactions (Array of Tx)
22 23 24 |
# File 'lib/bitcoin/protocol/block.rb', line 22 def tx @tx end |
#ver ⇒ Object
version (usually 1)
37 38 39 |
# File 'lib/bitcoin/protocol/block.rb', line 37 def ver @ver end |
Class Method Details
.binary_from_hash(h) ⇒ Object
convert ruby hash to raw binary
249 |
# File 'lib/bitcoin/protocol/block.rb', line 249 def self.binary_from_hash(h); from_hash(h).to_payload; end |
.binary_from_json(json_string) ⇒ Object
convert json representation to raw binary
255 |
# File 'lib/bitcoin/protocol/block.rb', line 255 def self.binary_from_json(json_string); from_json(json_string).to_payload; end |
.from_file(path) ⇒ Object
read binary block from a file
270 |
# File 'lib/bitcoin/protocol/block.rb', line 270 def self.from_file(path); new( Bitcoin::Protocol.read_binary_file(path) ); end |
.from_hash(h, do_raise = true) ⇒ Object
parse ruby hash (see also #to_hash)
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/bitcoin/protocol/block.rb', line 231 def self.from_hash(h, do_raise=true) blk = new(nil) blk.instance_eval{ @ver, @time, @bits, @nonce = h.values_at('ver', 'time', 'bits', 'nonce') @prev_block_hash, @mrkl_root = h.values_at('prev_block', 'mrkl_root').map{|i| i.htb_reverse } unless h['hash'] == recalc_block_hash raise "Block hash mismatch! Claimed: #{h['hash']}, Actual: #{@hash}" if do_raise end @aux_pow = AuxPow.from_hash(h['aux_pow']) if h['aux_pow'] h['tx'].each{|tx| @tx << Tx.from_hash(tx, do_raise) } if h['tx'].any? (raise "Block merkle root mismatch! Block: #{h['hash']}" unless verify_mrkl_root) if do_raise end } blk end |
.from_json(json_string) ⇒ Object
parse json representation (see also #to_json)
252 |
# File 'lib/bitcoin/protocol/block.rb', line 252 def self.from_json(json_string); from_hash( JSON.load(json_string) ); end |
.from_json_file(path) ⇒ Object
read json block from a file
273 |
# File 'lib/bitcoin/protocol/block.rb', line 273 def self.from_json_file(path); from_json( Bitcoin::Protocol.read_binary_file(path) ); end |
Instance Method Details
#==(other) ⇒ Object
compare to another block
50 51 52 |
# File 'lib/bitcoin/protocol/block.rb', line 50 def ==(other) @hash == other.hash end |
#binary_hash ⇒ Object
54 55 56 |
# File 'lib/bitcoin/protocol/block.rb', line 54 def binary_hash [@hash].pack("H*") end |
#bip34_block_height(height = nil) ⇒ Object
introduced in block version 2 by BIP_0034 blockchain height as seen by the block itself. do not trust this value, instead verify with chain storage.
205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/bitcoin/protocol/block.rb', line 205 def bip34_block_height(height=nil) return nil unless @ver >= 2 if height # generate height binary buf = [height].pack("V").gsub(/\x00+$/,"") [buf.bytesize, buf].pack("Ca*") else coinbase = @tx.first.inputs.first.script_sig coinbase[1..coinbase[0].ord].ljust(4, "\x00").unpack("V").first end rescue nil end |
#block_header ⇒ Object
block header binary output
265 266 267 |
# File 'lib/bitcoin/protocol/block.rb', line 265 def block_header [@ver, @prev_block_hash, @mrkl_root, @time, @bits, @nonce, Protocol.pack_var_int(0)].pack("Va32a32VVVa*") end |
#block_work ⇒ Object
get the (statistical) amount of work that was needed to generate this block.
276 277 278 279 280 |
# File 'lib/bitcoin/protocol/block.rb', line 276 def block_work target = Bitcoin.decode_compact_bits(@bits).to_i(16) return 0 if target <= 0 (2**256) / (target + 1) end |
#decimaltarget ⇒ Object
194 195 196 |
# File 'lib/bitcoin/protocol/block.rb', line 194 def decimaltarget Bitcoin.decode_compact_bits(@bits).to_i(16) end |
#difficulty ⇒ Object
198 199 200 |
# File 'lib/bitcoin/protocol/block.rb', line 198 def difficulty Bitcoin.block_difficulty(@bits) end |
#header_info ⇒ Object
get the block header info
- <version>, <prev_block>, <merkle_root>, <time>, <bits>, <nonce>, <txcount>, <size>
158 159 160 |
# File 'lib/bitcoin/protocol/block.rb', line 158 def header_info [@ver, @prev_block_hash.reverse_hth, @mrkl_root.reverse_hth, Time.at(@time), @bits, @nonce, @tx.size, @payload.size] end |
#header_to_json(options = {:space => ''}) ⇒ Object
convert header to json representation.
258 259 260 261 262 |
# File 'lib/bitcoin/protocol/block.rb', line 258 def header_to_json( = {:space => ''}) h = to_hash %w[tx mrkl_tree].each{|k| h.delete(k) } JSON.pretty_generate( h, ) end |
#hextarget ⇒ Object
190 191 192 |
# File 'lib/bitcoin/protocol/block.rb', line 190 def hextarget Bitcoin.decode_compact_bits(@bits) end |
#parse_data(data) ⇒ Object
parse raw binary data
69 70 71 72 |
# File 'lib/bitcoin/protocol/block.rb', line 69 def parse_data(data) buf = parse_data_from_io(data) buf.eof? ? true : buf.read end |
#parse_data_from_io(buf, header_only = false) ⇒ Object
parse raw binary data
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 |
# File 'lib/bitcoin/protocol/block.rb', line 75 def parse_data_from_io(buf, header_only=false) buf = buf.is_a?(String) ? StringIO.new(buf) : buf @ver, @prev_block_hash, @mrkl_root, @time, @bits, @nonce = buf.read(80).unpack("Va32a32VVV") recalc_block_hash if Bitcoin.network[:auxpow_chain_id] != nil && (@ver & BLOCK_VERSION_AUXPOW) > 0 @aux_pow = AuxPow.new(nil) @aux_pow.parse_data_from_io(buf) end return buf if buf.eof? if header_only == :filtered @tx_count = buf.read(4).unpack("V")[0] nhashes = Protocol.unpack_var_int_from_io(buf) hashes = [] nhashes.times do hashes << buf.read(256 / 8) end nflags = Protocol.unpack_var_int_from_io(buf) flags = buf.read(nflags) @partial_merkle_tree = PartialMerkleTree.new(@tx_count, hashes, flags) @partial_merkle_tree.set_value return buf end 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 return buf if buf.eof? t = Tx.new(nil) payload = t.parse_data_from_io(buf) @tx << t } @payload = to_payload buf end |
#prev_block=(hash) ⇒ Object
19 |
# File 'lib/bitcoin/protocol/block.rb', line 19 def prev_block=(hash); @prev_block_hash = hash; end |
#prev_block_hex ⇒ Object
58 59 60 |
# File 'lib/bitcoin/protocol/block.rb', line 58 def prev_block_hex @prev_block_hex ||= @prev_block_hash.reverse.unpack("H*")[0] end |
#recalc_block_hash ⇒ Object
recalculate the block hash
123 124 125 |
# File 'lib/bitcoin/protocol/block.rb', line 123 def recalc_block_hash @hash = Bitcoin.block_hash(@prev_block_hash.reverse_hth, @mrkl_root.reverse_hth, @time, @bits, @nonce, @ver) end |
#recalc_block_scrypt_hash ⇒ Object
127 128 129 |
# File 'lib/bitcoin/protocol/block.rb', line 127 def recalc_block_scrypt_hash @scrypt_hash = Bitcoin.block_scrypt_hash(@prev_block_hash.reverse_hth, @mrkl_root.reverse_hth, @time, @bits, @nonce, @ver) end |
#recalc_mrkl_root ⇒ Object
131 132 133 134 135 136 137 |
# File 'lib/bitcoin/protocol/block.rb', line 131 def recalc_mrkl_root @mrkl_root = if partial_merkle_tree partial_merkle_tree.root.value.htb_reverse else Bitcoin.hash_mrkl_tree( @tx.map(&:hash) ).last.htb_reverse end end |
#size ⇒ Object
186 187 188 |
# File 'lib/bitcoin/protocol/block.rb', line 186 def size payload.bytesize end |
#to_hash(options = {}) ⇒ Object
convert to ruby hash (see also #from_hash)
173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/bitcoin/protocol/block.rb', line 173 def to_hash( = {}) h = { 'hash' => @hash, 'ver' => @ver, 'prev_block' => @prev_block_hash.reverse_hth, 'mrkl_root' => @mrkl_root.reverse_hth, 'time' => @time, 'bits' => @bits, 'nonce' => @nonce, 'n_tx' => @tx.size, 'size' => (@payload||to_payload).bytesize, 'tx' => @tx.map{|i| i.to_hash() }, 'mrkl_tree' => Bitcoin.hash_mrkl_tree( @tx.map{|i| i.hash } ) } h['aux_pow'] = @aux_pow.to_hash if @aux_pow h end |
#to_json(options = {:space => ''}, *a) ⇒ Object
convert to json representation as seen in the block explorer. (see also #from_json)
220 221 222 |
# File 'lib/bitcoin/protocol/block.rb', line 220 def to_json( = {:space => ''}, *a) JSON.pretty_generate( to_hash(), ) end |
#to_json_file(path) ⇒ Object
write json representation to a file (see also #to_json)
226 227 228 |
# File 'lib/bitcoin/protocol/block.rb', line 226 def to_json_file(path) File.open(path, 'wb'){|f| f.print to_json; } end |
#to_payload ⇒ Object
convert to raw binary format
163 164 165 166 167 168 169 170 |
# File 'lib/bitcoin/protocol/block.rb', line 163 def to_payload head = [@ver, @prev_block_hash, @mrkl_root, @time, @bits, @nonce].pack("Va32a32VVV") head << @aux_pow.to_payload if @aux_pow return head if @tx.size == 0 head << Protocol.pack_var_int(@tx.size) @tx.each{|tx| head << tx.to_payload } head end |
#tx_hashes ⇒ Object
148 149 150 151 152 153 154 |
# File 'lib/bitcoin/protocol/block.rb', line 148 def tx_hashes if partial_merkle_tree partial_merkle_tree.tx_hashes else @tx.map(&:hash) end end |
#verify_mrkl_root ⇒ Object
verify mrkl tree
140 141 142 143 144 145 146 |
# File 'lib/bitcoin/protocol/block.rb', line 140 def verify_mrkl_root if partial_merkle_tree partial_merkle_tree.valid_tree?(@mrkl_root.reverse_hth) else @mrkl_root.reverse_hth == Bitcoin.hash_mrkl_tree( @tx.map(&:hash) ).last end end |