Module: Bitcoin::Protocol

Defined in:
lib/bitcoin/protocol.rb,
lib/bitcoin/protocol/tx.rb,
lib/bitcoin/protocol/txin.rb,
lib/bitcoin/protocol/block.rb,
lib/bitcoin/protocol/txout.rb,
lib/bitcoin/protocol/alert.rb,
lib/bitcoin/protocol/parser.rb,
lib/bitcoin/protocol/version.rb,
lib/bitcoin/protocol/handler.rb,
lib/bitcoin/protocol/aux_pow.rb,
lib/bitcoin/protocol/address.rb

Defined Under Namespace

Classes: Addr, Alert, AuxPow, Block, Handler, Parser, Tx, TxIn, TxOut, Version

Constant Summary

MAX_INV_SZ =

bitcoin/src/main.h

50000
BIP0031_VERSION =

BIP 0031, pong message, is enabled for all versions AFTER this one

60000
Uniq =
rand(0xffffffffffffffff)
BINARY =
Encoding.find('ASCII-8BIT')
TypeLookup =
Hash[:tx, 1, :block, 2, nil, 0]
DEFAULT_STOP_HASH =
"00"*32

Class Method Summary (collapse)

Class Method Details

+ (Object) getblocks_pkt(version, locator_hashes, stop_hash = DEFAULT_STOP_HASH)



147
148
149
# File 'lib/bitcoin/protocol.rb', line 147

def self.getblocks_pkt(version, locator_hashes, stop_hash=DEFAULT_STOP_HASH)
  pkt "getblocks",  locator_payload(version, locator_hashes, stop_hash)
end

+ (Object) getdata_pkt(type, hashes)



124
125
126
127
128
# File 'lib/bitcoin/protocol.rb', line 124

def self.getdata_pkt(type, hashes)
  return if hashes.size > MAX_INV_SZ
  t = [ TypeLookup[type] ].pack("V")
  pkt("getdata", pack_var_int(hashes.size) + hashes.map{|hash| t + hash[0..32].reverse }.join)
end

+ (Object) getheaders_pkt(version, locator_hashes, stop_hash = DEFAULT_STOP_HASH)



151
152
153
# File 'lib/bitcoin/protocol.rb', line 151

def self.getheaders_pkt(version, locator_hashes, stop_hash=DEFAULT_STOP_HASH)
  pkt "getheaders", locator_payload(version, locator_hashes, stop_hash)
end

+ (Object) inv_pkt(type, hashes)



130
131
132
133
134
# File 'lib/bitcoin/protocol.rb', line 130

def self.inv_pkt(type, hashes)
  return if hashes.size > MAX_INV_SZ
  t = [ TypeLookup[type] ].pack("V")
  pkt("inv", pack_var_int(hashes.size) + hashes.map{|hash| t + hash[0..32].reverse }.join)
end

+ (Object) locator_payload(version, locator_hashes, stop_hash)



138
139
140
141
142
143
144
145
# File 'lib/bitcoin/protocol.rb', line 138

def self.locator_payload(version, locator_hashes, stop_hash)
  payload = [
    [version].pack("V"),
    pack_var_int(locator_hashes.size),
    locator_hashes.map{|l| l.htb_reverse }.join,
    stop_hash.htb_reverse
  ].join
end

+ (Object) pack_var_int(i)



51
52
53
54
55
56
57
58
# File 'lib/bitcoin/protocol.rb', line 51

def self.pack_var_int(i)
  if    i <  0xfd;                [      i].pack("C")
  elsif i <= 0xffff;              [0xfd, i].pack("Cv")
  elsif i <= 0xffffffff;          [0xfe, i].pack("CV")
  elsif i <= 0xffffffffffffffff;  [0xff, i].pack("CQ")
  else raise "int(#{i}) too large!"
  end
end

+ (Object) pack_var_string(payload)



70
71
72
# File 'lib/bitcoin/protocol.rb', line 70

def self.pack_var_string(payload)
  pack_var_int(payload.bytesize) + payload
end

+ (Object) ping_pkt(nonce = rand(0xffffffff))



110
111
112
# File 'lib/bitcoin/protocol.rb', line 110

def self.ping_pkt(nonce = rand(0xffffffff))
  pkt("ping", [nonce].pack("Q"))
end

+ (Object) pkt(command, payload)



88
89
90
91
92
93
94
# File 'lib/bitcoin/protocol.rb', line 88

def self.pkt(command, payload)
  cmd      = command.ljust(12, "\x00")[0...12]
  length   = [payload.bytesize].pack("V")
  checksum = Digest::SHA256.digest(Digest::SHA256.digest(payload))[0...4]
  pkt      = "".force_encoding(BINARY)
  pkt << Bitcoin.network[:magic_head].force_encoding(BINARY) << cmd.force_encoding(BINARY) << length << checksum << payload.force_encoding(BINARY)
end

+ (Object) pong_pkt(nonce)



114
115
116
# File 'lib/bitcoin/protocol.rb', line 114

def self.pong_pkt(nonce)
  pkt("pong", [nonce].pack("Q"))
end

+ (Object) read_binary_file(path)



155
156
157
# File 'lib/bitcoin/protocol.rb', line 155

def self.read_binary_file(path)
  File.open(path, 'rb'){|f| f.read }
end

+ (Object) unpack_var_int(payload)

var_int refers to en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer and is what Satoshi called “CompactSize” BitcoinQT has later added even more compact format called CVarInt to use in its local block storage. CVarInt is not implemented here.



32
33
34
35
36
37
38
39
# File 'lib/bitcoin/protocol.rb', line 32

def self.unpack_var_int(payload)
  case payload.unpack("C")[0] # TODO add test cases
  when 0xfd; payload.unpack("xva*")
  when 0xfe; payload.unpack("xVa*")
  when 0xff; payload.unpack("xQa*") # TODO add little-endian version of Q
  else;      payload.unpack("Ca*")
  end
end

+ (Object) unpack_var_int_array(payload)

unpacks set<int>



80
81
82
83
84
# File 'lib/bitcoin/protocol.rb', line 80

def self.unpack_var_int_array(payload) # unpacks set<int>
  size, payload = unpack_var_int(payload)
  return [nil, payload] if size == 0
  [(0...size).map{ i, payload = unpack_var_int(payload); i }, payload]
end

+ (Object) unpack_var_int_from_io(io)



41
42
43
44
45
46
47
48
49
# File 'lib/bitcoin/protocol.rb', line 41

def self.unpack_var_int_from_io(io)
  uchar = io.read(1).unpack("C")[0]
  case uchar
  when 0xfd; io.read(2).unpack("v")[0]
  when 0xfe; io.read(4).unpack("V")[0]
  when 0xff; io.read(8).unpack("Q")[0]
  else;      uchar
  end
end

+ (Object) unpack_var_string(payload)



60
61
62
63
# File 'lib/bitcoin/protocol.rb', line 60

def self.unpack_var_string(payload)
  size, payload = unpack_var_int(payload)
  size > 0 ? (string, payload = payload.unpack("a#{size}a*")) : [nil, payload]
end

+ (Object) unpack_var_string_array(payload)

unpacks set<string>



74
75
76
77
78
# File 'lib/bitcoin/protocol.rb', line 74

def self.unpack_var_string_array(payload) # unpacks set<string>
  size, payload = unpack_var_int(payload)
  return [nil, payload] if size == 0
  [(0...size).map{ s, payload = unpack_var_string(payload); s }, payload]
end

+ (Object) unpack_var_string_from_io(buf)



65
66
67
68
# File 'lib/bitcoin/protocol.rb', line 65

def self.unpack_var_string_from_io(buf)
  size = unpack_var_int_from_io(buf)
  size > 0 ? buf.read(size) : nil
end

+ (Object) verack_pkt



118
119
120
# File 'lib/bitcoin/protocol.rb', line 118

def self.verack_pkt
  pkt("verack", "")
end

+ (Object) version_pkt(from_id, from = nil, to = nil, last_block = nil, time = nil, user_agent = nil, version = nil)



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/bitcoin/protocol.rb', line 96

def self.version_pkt(from_id, from=nil, to=nil, last_block=nil, time=nil, user_agent=nil, version=nil)
  opts = if from_id.is_a?(Hash)
    from_id
  else
    STDERR.puts "Bitcoin::Protocol.version_pkt - API deprecated. please change it soon.."
    {
      :nonce => from_id, :from => from, :to => to, :last_block => last_block,
      :time => time, :user_agent => user_agent, :version => version
    }
  end
  version = Protocol::Version.new(opts)
  version.to_pkt
end