Class: Bitcoin::Block

Inherits:
Object
  • Object
show all
Defined in:
lib/bitcoin/block.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(header, transactions = []) ⇒ Block

Constructor

Parameters:

Raises:

  • (ArgumentError)


11
12
13
14
15
16
# File 'lib/bitcoin/block.rb', line 11

def initialize(header, transactions = [])
  raise ArgumentError, "header must be Bitcoin::BlockHeader." unless header.is_a?(Bitcoin::BlockHeader)
  raise ArgumentError, "transactions must be an Array." unless transactions.is_a?(Array)
  @header = header
  @transactions = transactions
end

Instance Attribute Details

#headerObject

Returns the value of attribute header.



4
5
6
# File 'lib/bitcoin/block.rb', line 4

def header
  @header
end

#transactionsObject

Returns the value of attribute transactions.



5
6
7
# File 'lib/bitcoin/block.rb', line 5

def transactions
  @transactions
end

Class Method Details

.create_genesis(msg, script, time, nonce, bits, version, rewards = 50 * 100000000) ⇒ Object

Create genesis block.

Parameters:

  • msg (String)

    Message embedded in coinbase transaction.

  • script (Bitcoin::Script)

    Coinbase transaction scriptPubkey.

  • time (Integer)

    Block time.

  • nonce (Integer)

    nonce.

  • bits (Integer)

    nBits

  • version (Integer)

    nVersion.

  • rewards (Integer) (defaults to: 50 * 100000000)

    Block rewards(satoshi).



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/bitcoin/block.rb', line 26

def self.create_genesis(msg, script, time, nonce, bits, version, rewards = 50 * 100000000)
  coinbase = Bitcoin::Tx.create_coinbase(msg, script, rewards)
  header = BlockHeader.new(
    version,
    '00' * 32,
    MerkleTree.build_from_leaf([coinbase.txid]).merkle_root.rhex,
    time,
    bits,
    nonce
  )
  Block.new(header, [coinbase])
end

.parse_from_payload(payload) ⇒ Object



39
40
41
# File 'lib/bitcoin/block.rb', line 39

def self.parse_from_payload(payload)
  Bitcoin::Message::Block.parse_from_payload(payload).to_block
end

Instance Method Details

#block_hashObject



47
48
49
# File 'lib/bitcoin/block.rb', line 47

def block_hash
  header.block_hash
end

#calculate_merkle_rootObject

calculate merkle root from tx list.



74
75
76
# File 'lib/bitcoin/block.rb', line 74

def calculate_merkle_root
  Bitcoin::MerkleTree.build_from_leaf(transactions.map(&:tx_hash)).merkle_root
end

#calculate_witness_commitmentObject

calculate witness commitment from tx list.



84
85
86
87
88
89
90
# File 'lib/bitcoin/block.rb', line 84

def calculate_witness_commitment
  witness_hashes = [COINBASE_WTXID]
  witness_hashes += (transactions[1..-1].map(&:witness_hash))
  reserved_value = transactions[0].inputs[0].script_witness.stack.map(&:bth).join
  root_hash = Bitcoin::MerkleTree.build_from_leaf(witness_hashes).merkle_root
  Bitcoin.double_sha256([root_hash + reserved_value].pack('H*')).bth
end

#hashObject



43
44
45
# File 'lib/bitcoin/block.rb', line 43

def hash
  header.hash
end

#heightObject

return this block height. block height is included in coinbase. if block version under 1, height does not include in coinbase, so return nil.



94
95
96
97
98
99
100
101
# File 'lib/bitcoin/block.rb', line 94

def height
  return nil if header.version < 2
  coinbase_tx = transactions[0]
  return nil unless coinbase_tx.coinbase_tx?
  buf = StringIO.new(coinbase_tx.inputs[0].script_sig.to_payload)
  len = Bitcoin.unpack_var_int_from_io(buf)
  buf.read(len).reverse.bth.to_i(16)
end

#sizeObject

calculate total size (include witness data.)



57
58
59
60
# File 'lib/bitcoin/block.rb', line 57

def size
  80 + Bitcoin.pack_var_int(transactions.size).bytesize +
      transactions.inject(0){|sum, tx| sum + (tx.witness? ? tx.serialize_witness_format.bytesize : tx.serialize_old_format.bytesize)}
end

#stripped_sizeObject

calculate base size (not include witness data.)



63
64
65
66
# File 'lib/bitcoin/block.rb', line 63

def stripped_size
  80 + Bitcoin.pack_var_int(transactions.size).bytesize +
      transactions.inject(0){|sum, tx| sum + tx.serialize_old_format.bytesize}
end

#valid_merkle_root?Boolean

check the merkle root in the block header matches merkle root calculated from tx list.

Returns:

  • (Boolean)


69
70
71
# File 'lib/bitcoin/block.rb', line 69

def valid_merkle_root?
  calculate_merkle_root == header.merkle_root
end

#valid_witness_commitment?Boolean

check the witness commitment in coinbase tx matches witness commitment calculated from tx list.

Returns:

  • (Boolean)


79
80
81
# File 'lib/bitcoin/block.rb', line 79

def valid_witness_commitment?
  transactions[0].witness_commitment == calculate_witness_commitment
end

#weightObject

calculate block weight



52
53
54
# File 'lib/bitcoin/block.rb', line 52

def weight
  stripped_size * (WITNESS_SCALE_FACTOR - 1) + size
end