Class: Bitcoin::Protocol::Version

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

Overview

Constant Summary collapse

NODE_NONE =

services bit constants

0
NODE_NETWORK =
(1 << 0)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Version

Returns a new instance of Version.



14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/bitcoin/protocol/version.rb', line 14

def initialize(opts={})
  @fields = {
    :version    => Bitcoin.network[:protocol_version],
    :services   => NODE_NETWORK,
    :time       => Time.now.tv_sec,
    :from       => "127.0.0.1:8333",
    :to         => "127.0.0.1:8333",
    :nonce      => Bitcoin::Protocol::Uniq,
    :user_agent => "/bitcoin-ruby:#{Bitcoin::VERSION}/",
    :last_block => 0, # 188617
    :relay      => true # BIP0037
  }.merge( opts.reject{|k,v| v == nil } )
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*a) ⇒ Object



82
# File 'lib/bitcoin/protocol/version.rb', line 82

def method_missing(*a); (@fields[a.first] rescue nil) or super(*a); end

Instance Attribute Details

#fieldsObject (readonly)

Returns the value of attribute fields.



12
13
14
# File 'lib/bitcoin/protocol/version.rb', line 12

def fields
  @fields
end

Class Method Details

.parse(payload) ⇒ Object



84
# File 'lib/bitcoin/protocol/version.rb', line 84

def self.parse(payload); new.parse(payload); end

Instance Method Details

#pack_address_field(addr_str) ⇒ Object



64
65
66
67
68
69
70
71
# File 'lib/bitcoin/protocol/version.rb', line 64

def pack_address_field(addr_str)
  host, port = addr_str.split(":")
  port = port ? port.to_i : 8333
  sockaddr = Socket.pack_sockaddr_in(port, host)
  #raise "invalid IPv4 Address: #{addr}" unless sockaddr[0...2] == "\x02\x00"
  port, host = sockaddr[2...4], sockaddr[4...8]
  [[1].pack("Q"), "\x00"*10, "\xFF\xFF",  host, port].join
end

#parse(payload) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/bitcoin/protocol/version.rb', line 44

def parse(payload)
  version, services, timestamp, to, from, nonce, payload = payload.unpack("VQQa26a26Qa*")
  to, from = unpack_address_field(to), unpack_address_field(from)
  user_agent, payload = Protocol.unpack_var_string(payload)
  last_block, payload = payload.unpack("Va*")
  relay, payload = unpack_relay_field(version, payload)

  @fields = {
   :version => version, :services => services, :time => timestamp,
   :from => from, :to => to, :nonce => nonce,
   :user_agent => user_agent.to_s, :last_block => last_block, :relay => relay
  }
  self
end

#to_payloadObject



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/bitcoin/protocol/version.rb', line 28

def to_payload
  [
    @fields.values_at(:version, :services, :time).pack("VQQ"),
    pack_address_field(@fields[:from]),
    pack_address_field(@fields[:to]),
    @fields.values_at(:nonce).pack("Q"),
    Protocol.pack_var_string(@fields[:user_agent]),
    @fields.values_at(:last_block).pack("V"),
    Protocol.pack_boolean(@fields[:relay]) # Satoshi 0.8.6 doesn't send this but it does respect it
  ].join
end

#to_pktObject



40
41
42
# File 'lib/bitcoin/protocol/version.rb', line 40

def to_pkt
  Bitcoin::Protocol.pkt("version", to_payload)
end

#unpack_address_field(payload) ⇒ Object



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

def unpack_address_field(payload)
  ip, port = payload.unpack("x8x12a4n")
  "#{ip.unpack("C*").join(".")}:#{port}"
end

#unpack_relay_field(version, payload) ⇒ Object

BIP0037: this field starts with version 70001 and is allowed to be missing, defaults to true



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

def unpack_relay_field(version, payload)
  ( version >= 70001 and payload ) ? Protocol.unpack_boolean(payload) : [ true, nil ]
end

#uptimeObject



78
79
80
# File 'lib/bitcoin/protocol/version.rb', line 78

def uptime
  @fields[:time] - Time.now.tv_sec
end