Class: BTC::BlockHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/btcruby/block_header.rb

Overview

Block header is the 80-byte prefix of the block. Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce values to make the block’s hash satisfy proof-of-work requirements. When they solve the proof-of-work, they broadcast the block to everyone and the block is added to the block chain. The first transaction in the block is a special one that creates a new coin owned by the creator of the block.

Direct Known Subclasses

Block

Constant Summary collapse

CURRENT_VERSION =
2
ZERO_HASH256 =
"\x00".b*32

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data: nil, stream: nil, version: CURRENT_VERSION, previous_block_hash: nil, previous_block_id: nil, merkle_root: nil, timestamp: 0, time: nil, bits: 0, nonce: 0, height: nil, confirmations: nil) ⇒ BlockHeader

Returns a new instance of BlockHeader.



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
# File 'lib/btcruby/block_header.rb', line 78

def initialize(data: nil,
               stream: nil,
               version: CURRENT_VERSION,
               previous_block_hash: nil,
               previous_block_id: nil,
               merkle_root: nil,
               timestamp: 0,
               time: nil,
               bits: 0,
               nonce: 0,

               # optional attributes
               height: nil,
               confirmations: nil)

  if stream || data
    init_with_stream(stream || StringIO.new(data))
  else
    @version = version || CURRENT_VERSION
    @previous_block_hash = previous_block_hash || ZERO_HASH256
    @previous_block_hash = BTC.hash_from_id(previous_block_id) if previous_block_id
    @merkle_root = merkle_root || ZERO_HASH256
    @timestamp   = timestamp   || 0
    @timestamp   = time.to_i if time
    @bits        = bits        || 0
    @nonce       = nonce       || 0
  end

  @height = height
  @confirmations = confirmations
end

Instance Attribute Details

#bitsObject

uint32 proof-of-work in compact format



39
40
41
# File 'lib/btcruby/block_header.rb', line 39

def bits
  @bits
end

#block_hashObject (readonly)

Binary hash of the block



15
16
17
# File 'lib/btcruby/block_header.rb', line 15

def block_hash
  @block_hash
end

#block_idObject (readonly)

Hex big-endian hash of the block



18
19
20
# File 'lib/btcruby/block_header.rb', line 18

def block_id
  @block_id
end

#confirmationsObject

The number of blocks that have been processed since the previous block (including the block itself).



52
53
54
# File 'lib/btcruby/block_header.rb', line 52

def confirmations
  @confirmations
end

#heightObject

The distance from the first block in the chain (genesis block has height 0).



49
50
51
# File 'lib/btcruby/block_header.rb', line 49

def height
  @height
end

#merkle_rootObject

Raw binary root hash of the transaction merkle tree.



30
31
32
# File 'lib/btcruby/block_header.rb', line 30

def merkle_root
  @merkle_root
end

#nonceObject

uint32 nonce (used for mining iterations)



42
43
44
# File 'lib/btcruby/block_header.rb', line 42

def nonce
  @nonce
end

#previous_block_hashObject

Binary hash of the previous block



24
25
26
# File 'lib/btcruby/block_header.rb', line 24

def previous_block_hash
  @previous_block_hash
end

#previous_block_idObject

Hex big-endian hash of the previous block



27
28
29
# File 'lib/btcruby/block_header.rb', line 27

def previous_block_id
  @previous_block_id
end

#timeObject

Time object derived from timestamp



36
37
38
# File 'lib/btcruby/block_header.rb', line 36

def time
  @time
end

#timestampObject

uint32 unix timestamp



33
34
35
# File 'lib/btcruby/block_header.rb', line 33

def timestamp
  @timestamp
end

#versionObject

Block version.



21
22
23
# File 'lib/btcruby/block_header.rb', line 21

def version
  @version
end

Class Method Details

.genesis_mainnetObject



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/btcruby/block_header.rb', line 54

def self.genesis_mainnet
  self.new(
    version:             1,
    previous_block_hash: ZERO_HASH256,
    merkle_root:         BTC.from_hex("3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a"),
    timestamp:           1231006505,
    bits:                0x1d00ffff,
    nonce:               0x7c2bac1d,
    height:              0
  )
end

.genesis_testnetObject



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/btcruby/block_header.rb', line 66

def self.genesis_testnet
  self.new(
    version:             1,
    previous_block_hash: ZERO_HASH256,
    merkle_root:         BTC.from_hex("3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a"),
    timestamp:           1296688602,
    bits:                0x1d00ffff,
    nonce:               0x18aea41a,
    height:              0
  )
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



187
188
189
190
191
192
193
194
# File 'lib/btcruby/block_header.rb', line 187

def ==(other)
              @version == other.version &&
  @previous_block_hash == other.previous_block_hash &&
          @merkle_root == other.merkle_root &&
            @timestamp == other.timestamp &&
                 @bits == other.bits &&
                @nonce == other.nonce
end

#dataObject



172
173
174
# File 'lib/btcruby/block_header.rb', line 172

def data
  header_data
end

#dupObject



197
198
199
200
201
202
203
204
205
206
207
# File 'lib/btcruby/block_header.rb', line 197

def dup
  self.class.new(
    version:             self.version,
    previous_block_hash: self.previous_block_hash,
    merkle_root:         self.merkle_root,
    timestamp:           self.timestamp,
    bits:                self.bits,
    nonce:               self.nonce,
    height:              self.height,
    confirmations:       self.confirmations)
end

#header_dataObject

so that in subclass Block we don’t hash the entire block



176
177
178
179
180
181
182
183
184
185
# File 'lib/btcruby/block_header.rb', line 176

def header_data # so that in subclass Block we don't hash the entire block
  data = "".b
  data << BTC::WireFormat.encode_int32le(self.version)
  data << self.previous_block_hash
  data << self.merkle_root
  data << BTC::WireFormat.encode_uint32le(self.timestamp)
  data << BTC::WireFormat.encode_uint32le(self.bits)
  data << BTC::WireFormat.encode_uint32le(self.nonce)
  data
end

#init_with_stream(stream) ⇒ Object

Raises:

  • (ArgumentError)


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
# File 'lib/btcruby/block_header.rb', line 110

def init_with_stream(stream)
  raise ArgumentError, "Stream is missing" if !stream
  if stream.eof?
    raise ArgumentError, "Can't parse block header from stream because it is already closed."
  end

  if !(version = BTC::WireFormat.read_int32le(stream: stream).first)
    raise ArgumentError, "Failed to read block version prefix from the stream."
  end

  if !(prevhash = stream.read(32)) || prevhash.bytesize != 32
    raise ArgumentError, "Failed to read 32-byte previous_block_hash from the stream."
  end

  if !(mrklroot = stream.read(32)) || mrklroot.bytesize != 32
    raise ArgumentError, "Failed to read 32-byte block merkle_root from the stream."
  end

  if !(timestamp = BTC::WireFormat.read_uint32le(stream: stream).first)
    raise ArgumentError, "Failed to read 32-byte block timestamp from the stream."
  end

  if !(bits = BTC::WireFormat.read_uint32le(stream: stream).first)
    raise ArgumentError, "Failed to read 32-byte proof-of-work bits from the stream."
  end

  if !(nonce = BTC::WireFormat.read_uint32le(stream: stream).first)
    raise ArgumentError, "Failed to read 32-byte nonce from the stream."
  end

  @version = version
  @previous_block_hash = prevhash
  @merkle_root = mrklroot
  @timestamp = timestamp
  @bits = bits
  @nonce = nonce
end

#inspectObject



209
210
211
212
213
214
215
216
217
218
# File 'lib/btcruby/block_header.rb', line 209

def inspect
  %{#<#{self.class.name}:#{self.block_id[0,24]}} +
  %{ ver:#{self.version}} +
  %{ prev:#{self.previous_block_id[0,24]}} +
  %{ merkle_root:#{BTC.id_from_hash(self.merkle_root)[0,16]}} +
  %{ timestamp:#{self.timestamp}} +
  %{ bits:0x#{self.bits.to_s(16)}} +
  %{ nonce:0x#{self.nonce.to_s(16)}} +
  %{>}
end