class Bitcoin::Message::NetworkAddr

Constants

TYPE

Attributes

addr[RW]

Network address. The interpretation depends on networkID. If ipv4 or ipv6 this field is a IPAddr object, otherwise hex string.

net[RW]
port[RW]
services[RW]

The services the node advertised in its version message.

skip_time[R]
time[RW]

unix time. Nodes advertising their own IP address set this to the current time. Nodes advertising IP addresses they’ve connected to set this to the last time they connected to that node. Other nodes just relaying the IP address should not change the time. Nodes can use the time field to avoid relaying old addr messages.

Public Class Methods

load_addr_v2_payload(payload) click to toggle source

Load addr payload with addr v2 format.

# File lib/bitcoin/message/network_addr.rb, line 117
def self.load_addr_v2_payload(payload)
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
  addr = NetworkAddr.new(time: buf.read(4).unpack1('V'))
  addr.services = Bitcoin.unpack_var_int_from_io(buf)
  addr.net = buf.read(1).unpack1('C')
  raise Bitcoin::Message::Error, "Unknown network id: #{addr.net}" unless NETWORK_ID.value?(addr.net)
  addr_len = Bitcoin.unpack_var_int_from_io(buf)
  addr.addr = case addr.net 
              when NETWORK_ID[:ipv4]
                raise Bitcoin::Message::Error, "Invalid IPv4 address." unless addr_len == 4
                IPAddr::new_ntoh(buf.read(addr_len))
              when NETWORK_ID[:ipv6]
                raise Bitcoin::Message::Error, "Invalid IPv6 address." unless addr_len == 16
                a = IPAddr::new_ntoh(buf.read(addr_len))
                raise Bitcoin::Message::Error, "Invalid IPv6 address." if a.ipv4_mapped?
                a
              when NETWORK_ID[:tor_v2]
                raise Bitcoin::Message::Error, "Invalid Tor v2 address." unless addr_len == 10
                buf.read(addr_len).bth
              when NETWORK_ID[:tor_v3]
                raise Bitcoin::Message::Error, "Invalid Tor v3 address." unless addr_len == 32
                buf.read(addr_len).bth
              when NETWORK_ID[:i2p]
                raise Bitcoin::Message::Error, "Invalid I2P address." unless addr_len == 32
                buf.read(addr_len).bth
              when NETWORK_ID[:cjdns]
                raise Bitcoin::Message::Error, "Invalid CJDNS address." unless addr_len == 16
                a = IPAddr::new_ntoh(buf.read(addr_len))
                raise Bitcoin::Message::Error, "Invalid CJDNS address." unless a.to_s.start_with?('fc00:')
                a
              end
  addr.port = buf.read(2).unpack1('n')
  addr
end
load_legacy_payload(payload) click to toggle source

Load addr payload with legacy format.

# File lib/bitcoin/message/network_addr.rb, line 105
def self.load_legacy_payload(payload)
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
  has_time = buf.size > 26
  addr = NetworkAddr.new(time: nil)
  addr.time = buf.read(4).unpack1('V') if has_time
  addr.services = buf.read(8).unpack1('Q')
  addr.addr = IPAddr::new_ntoh(buf.read(16))
  addr.port = buf.read(2).unpack1('n')
  addr
end
local_addr() click to toggle source
# File lib/bitcoin/message/network_addr.rb, line 60
def self.local_addr
  addr = new
  addr.addr = IPAddr.new('127.0.0.1')
  addr.port = Bitcoin.chain_params.default_port
  addr.services = DEFAULT_SERVICE_FLAGS
  addr
end
new(ip: '127.0.0.1', port: Bitcoin.chain_params.default_port, services: DEFAULT_SERVICE_FLAGS, time: Time.now.to_i, net: NETWORK_ID[:ipv4]) click to toggle source
# File lib/bitcoin/message/network_addr.rb, line 33
def initialize(ip: '127.0.0.1', port: Bitcoin.chain_params.default_port,
               services: DEFAULT_SERVICE_FLAGS, time: Time.now.to_i, net: NETWORK_ID[:ipv4])
  @time = time
  @port = port
  @services = services
  @net = net
  case net
  when NETWORK_ID[:ipv4], NETWORK_ID[:ipv6]
    @addr = IPAddr.new(ip) if ip
  end
end
parse_from_payload(payload, type: TYPE[:legacy]) click to toggle source

Parse addr payload @param [String] payload payload of addr @param [Integer] type Address format type @return [NetworkAddr]

# File lib/bitcoin/message/network_addr.rb, line 49
def self.parse_from_payload(payload, type: TYPE[:legacy])
  case type
  when TYPE[:legacy]
    load_legacy_payload(payload)
  when TYPE[:addr_v2]
    load_addr_v2_payload(payload)
  else
    raise Bitcoin::Message::Error, "Unknown type: #{type}."
  end
end

Public Instance Methods

addr_string() click to toggle source

Show addr string. e.g 127.0.0.1

# File lib/bitcoin/message/network_addr.rb, line 69
def addr_string
  case net
  when NETWORK_ID[:ipv4]
    addr.native
  when NETWORK_ID[:ipv6]
    if addr.to_s.start_with?(INTERNAL_IN_IPV6_PREFIX)
      Base32.encode(addr.hton[6..-1]).downcase.delete('=') + ".internal"
    else
      addr.to_s
    end
  when NETWORK_ID[:tor_v2]
    Base32.encode(addr.htb).downcase + ".onion"
  when NETWORK_ID[:tor_v3]
    # TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
    pubkey = addr.htb
    checksum = OpenSSL::Digest.new('SHA3-256').digest('.onion checksum' + pubkey + "\x03")
    Base32.encode(pubkey + checksum[0...2] + "\x03").downcase + ".onion"
  when NETWORK_ID[:i2p]
    Base32.encode(addr.htb).downcase.delete('=') + ".b32.i2p"
  when NETWORK_ID[:cjdns]
    addr.to_s
  end
end
legacy_payload(skip_time) click to toggle source
# File lib/bitcoin/message/network_addr.rb, line 152
def legacy_payload(skip_time)
  p = ''
  p << [time].pack('V') unless skip_time
  ip = addr.ipv4? ? addr.ipv4_mapped : addr
  p << [services].pack('Q') << ip.hton << [port].pack('n')
end
to_payload(skip_time = false, type: TYPE[:legacy]) click to toggle source
# File lib/bitcoin/message/network_addr.rb, line 93
def to_payload(skip_time = false, type: TYPE[:legacy])
  case type
  when TYPE[:legacy]
    legacy_payload(skip_time)
  when TYPE[:addr_v2]
    v2_payload
  else
    raise Bitcoin::Message::Error, "Unknown type: #{type}."
  end
end
v2_payload() click to toggle source
# File lib/bitcoin/message/network_addr.rb, line 159
def v2_payload
  p = [time].pack('V')
  p << Bitcoin.pack_var_int(services)
  p << [net].pack('C')
  case net
  when NETWORK_ID[:ipv4]
    p << Bitcoin.pack_var_int(4)
    p << addr.to_i.to_s(16).htb
  when NETWORK_ID[:ipv6]
    p << Bitcoin.pack_var_int(16)
    p << addr.hton
  when NETWORK_ID[:tor_v2]
    p << Bitcoin.pack_var_int(10)
  when NETWORK_ID[:tor_v3]
    p << Bitcoin.pack_var_int(32)
  when NETWORK_ID[:i2p]
    p << Bitcoin.pack_var_int(32)
  when NETWORK_ID[:cjdns]
    p << Bitcoin.pack_var_int(16)
  end
  p << [port].pack('n')
  p
end