Class: Bitcoin::Network::Peer

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

Overview

remote peer class.

Constant Summary collapse

PING_INTERVAL =

Interval for pinging peers.

2 * 60

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, port, pool, configuration) ⇒ Peer

Returns a new instance of Peer.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/bitcoin/network/peer.rb', line 37

def initialize(host, port, pool, configuration)
  @host = host
  @port = port
  @pool = pool
  @chain = pool.chain
  @connected = false
  @primary = false
  @logger = Bitcoin::Logger.create(:debug)
  @outbound = true
  @best_hash = -1
  @best_height = -1
  @min_ping = -1
  @bytes_sent = 0
  @bytes_recv = 0
  @relay = configuration.conf[:relay]
  current_height = @chain.latest_block.height
  remote_addr = Bitcoin::Message::NetworkAddr.new(ip: host, port: port, time: nil)
  @local_version = Bitcoin::Message::Version.new(remote_addr: remote_addr, start_height: current_height, relay: @relay)
end

Instance Attribute Details

#best_hashObject

Returns the value of attribute best_hash.



23
24
25
# File 'lib/bitcoin/network/peer.rb', line 23

def best_hash
  @best_hash
end

#best_heightObject

Returns the value of attribute best_height.



24
25
26
# File 'lib/bitcoin/network/peer.rb', line 24

def best_height
  @best_height
end

#bytes_recvObject

Returns the value of attribute bytes_recv.



16
17
18
# File 'lib/bitcoin/network/peer.rb', line 16

def bytes_recv
  @bytes_recv
end

#bytes_sentObject

Returns the value of attribute bytes_sent.



15
16
17
# File 'lib/bitcoin/network/peer.rb', line 15

def bytes_sent
  @bytes_sent
end

#chainObject (readonly)

Returns the value of attribute chain.



34
35
36
# File 'lib/bitcoin/network/peer.rb', line 34

def chain
  @chain
end

#connObject

remote peer connection



29
30
31
# File 'lib/bitcoin/network/peer.rb', line 29

def conn
  @conn
end

#conn_timeObject

Returns the value of attribute conn_time.



17
18
19
# File 'lib/bitcoin/network/peer.rb', line 17

def conn_time
  @conn_time
end

#connectedObject

Returns the value of attribute connected.



30
31
32
# File 'lib/bitcoin/network/peer.rb', line 30

def connected
  @connected
end

#fee_rateObject

Returns the value of attribute fee_rate.



35
36
37
# File 'lib/bitcoin/network/peer.rb', line 35

def fee_rate
  @fee_rate
end

#hostObject (readonly)

remote peer info



26
27
28
# File 'lib/bitcoin/network/peer.rb', line 26

def host
  @host
end

#idObject

Returns the value of attribute id.



11
12
13
# File 'lib/bitcoin/network/peer.rb', line 11

def id
  @id
end

#last_pingObject

Returns the value of attribute last_ping.



18
19
20
# File 'lib/bitcoin/network/peer.rb', line 18

def last_ping
  @last_ping
end

#last_ping_nonceObject

Returns the value of attribute last_ping_nonce.



19
20
21
# File 'lib/bitcoin/network/peer.rb', line 19

def last_ping_nonce
  @last_ping_nonce
end

#last_pongObject

Returns the value of attribute last_pong.



20
21
22
# File 'lib/bitcoin/network/peer.rb', line 20

def last_pong
  @last_pong
end

#last_recvObject

Returns the value of attribute last_recv.



14
15
16
# File 'lib/bitcoin/network/peer.rb', line 14

def last_recv
  @last_recv
end

#last_sendObject

Returns the value of attribute last_send.



13
14
15
# File 'lib/bitcoin/network/peer.rb', line 13

def last_send
  @last_send
end

#local_versionObject

Returns the value of attribute local_version.



12
13
14
# File 'lib/bitcoin/network/peer.rb', line 12

def local_version
  @local_version
end

#loggerObject (readonly)

Returns the value of attribute logger.



10
11
12
# File 'lib/bitcoin/network/peer.rb', line 10

def logger
  @logger
end

#min_pingObject

Returns the value of attribute min_ping.



21
22
23
# File 'lib/bitcoin/network/peer.rb', line 21

def min_ping
  @min_ping
end

#outboundObject

TODO need implements to accept inbound connection



22
23
24
# File 'lib/bitcoin/network/peer.rb', line 22

def outbound
  @outbound
end

#poolObject (readonly)

parent pool



33
34
35
# File 'lib/bitcoin/network/peer.rb', line 33

def pool
  @pool
end

#portObject (readonly)

Returns the value of attribute port.



27
28
29
# File 'lib/bitcoin/network/peer.rb', line 27

def port
  @port
end

#primaryObject

Returns the value of attribute primary.



31
32
33
# File 'lib/bitcoin/network/peer.rb', line 31

def primary
  @primary
end

Instance Method Details

#addrObject



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

def addr
  "#{host}:#{port}"
end

#block_typeObject

get peer’s block type.



125
126
127
# File 'lib/bitcoin/network/peer.rb', line 125

def block_type
  Bitcoin::Message::Inventory::MSG_FILTERED_BLOCK # TODO need other implementation
end

#broadcast_tx(tx) ⇒ Object

broadcast tx.



106
107
108
# File 'lib/bitcoin/network/peer.rb', line 106

def broadcast_tx(tx)
  conn.send_message(Bitcoin::Message::Tx.new(tx, support_witness?))
end

#close(msg = '') ⇒ Object

close peer connection.



165
166
167
# File 'lib/bitcoin/network/peer.rb', line 165

def close(msg = '')
  conn.close(msg)
end

#connectObject



57
58
59
# File 'lib/bitcoin/network/peer.rb', line 57

def connect
  self.conn ||= EM.connect(host, port, Bitcoin::Network::Connection, self)
end

#connected?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/bitcoin/network/peer.rb', line 61

def connected?
  @connected
end

#handle_block_inv(hashes) ⇒ Object

handle block inv message.



183
184
185
186
187
# File 'lib/bitcoin/network/peer.rb', line 183

def handle_block_inv(hashes)
  getdata = Bitcoin::Message::GetData.new(
      hashes.map{|h|Bitcoin::Message::Inventory.new(block_type, h)})
  conn.send_message(getdata)
end

#handle_error(e) ⇒ Object

handle error



156
157
158
# File 'lib/bitcoin/network/peer.rb', line 156

def handle_error(e)
  pool.handle_error(e)
end

#handle_headers(headers) ⇒ Object

handle headers message



142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/bitcoin/network/peer.rb', line 142

def handle_headers(headers)
  headers.headers.each do |header|
    break unless header.valid?
    entry = chain.append_header(header)
    next unless entry
    @best_hash = entry.block_hash
    @best_height = entry.height
  end
  pool.changed
  pool.notify_observers(:header, {hash: @best_hash, height: @best_height})
  start_block_header_download if headers.headers.size > 0 # next header download
end

#handle_merkle_block(merkle_block) ⇒ Object



194
195
196
197
# File 'lib/bitcoin/network/peer.rb', line 194

def handle_merkle_block(merkle_block)
  pool.changed
  pool.notify_observers(:merkleblock, merkle_block)
end

#handle_tx(tx) ⇒ Object



189
190
191
192
# File 'lib/bitcoin/network/peer.rb', line 189

def handle_tx(tx)
  pool.changed
  pool.notify_observers(:tx, tx)
end

#outbound?Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/bitcoin/network/peer.rb', line 65

def outbound?
  @outbound
end

#ping_timeObject

calculate ping-pong time.



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

def ping_time
  last_pong ? (last_pong - last_ping) / 1e6 : -1
end

#post_handshakeObject



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/bitcoin/network/peer.rb', line 84

def post_handshake
  @connected = true
  if remote_version.support?(Bitcoin::Message::SERVICE_FLAGS[:bloom])
    pool.handle_new_peer(self)
    # require remote peer to use headers message instead fo inv message.
    conn.send_message(Bitcoin::Message::SendHeaders.new)
    EM.add_periodic_timer(PING_INTERVAL) {send_ping}
  else
    close("peer does not support NODE_BLOOM.")
    pool.pending_peers.delete(self)
  end
end

#primary?Boolean

Whether to try and download blocks and transactions from this peer.

Returns:

  • (Boolean)


136
137
138
# File 'lib/bitcoin/network/peer.rb', line 136

def primary?
  primary
end

#remote_versionBitcoin::Message::Version

get remote peer’s version message.



131
132
133
# File 'lib/bitcoin/network/peer.rb', line 131

def remote_version
  conn.version
end

#send_addrsObject

send addr message to remote peer



177
178
179
180
# File 'lib/bitcoin/network/peer.rb', line 177

def send_addrs
  addrs = pool.peers.select{|p|p != self}.map(&:to_network_addr)
  conn.send_message(Bitcoin::Message::Addr.new(addrs))
end

#send_filter_add(element) ⇒ Object

send filteradd message.



216
217
218
219
# File 'lib/bitcoin/network/peer.rb', line 216

def send_filter_add(element)
  filter_add = Bitcoin::Message::FilterAdd.new(element)
  conn.send_message(filter_add)
end

#send_filter_clearObject

send filterclear message.



222
223
224
225
# File 'lib/bitcoin/network/peer.rb', line 222

def send_filter_clear
  filter_clear = Bitcoin::Message::FilterClear.new
  conn.send_message(filter_clear)
end

#send_filter_load(bloom) ⇒ Object

send filterload message.



209
210
211
212
213
# File 'lib/bitcoin/network/peer.rb', line 209

def send_filter_load(bloom)
  filter_load = Bitcoin::Message::FilterLoad.new(
      bloom, Bitcoin::Message::FilterLoad::BLOOM_UPDATE_ALL)
  conn.send_message(filter_load)
end

#send_pingObject

send ping message.



200
201
202
203
204
205
206
# File 'lib/bitcoin/network/peer.rb', line 200

def send_ping
  ping = Bitcoin::Message::Ping.new
  @last_ping = Time.now.to_i
  @last_pong = -1
  @last_ping_nonce = ping.nonce
  conn.send_message(ping)
end

#start_block_header_downloadObject

start block header download



98
99
100
101
102
103
# File 'lib/bitcoin/network/peer.rb', line 98

def start_block_header_download
  logger.info("[#{addr}] start block header download.")
  get_headers = Bitcoin::Message::GetHeaders.new(
      Bitcoin.chain_params.protocol_version, [chain.latest_block.block_hash])
  conn.send_message(get_headers)
end

#support_cmpct?Boolean

check the remote peer supports compact block.

Returns:

  • (Boolean)


117
118
119
120
121
122
# File 'lib/bitcoin/network/peer.rb', line 117

def support_cmpct?
  return false if remote_version.version < Bitcoin::Message::VERSION[:compact]
  return true unless local_version.services & Bitcoin::Message::SERVICE_FLAGS[:witness] > 0
  return false unless support_witness?
  remote_version.version >= Bitcoin::Message::VERSION[:compact_witness]
end

#support_witness?Boolean

check the remote peer support witness.

Returns:

  • (Boolean)


111
112
113
114
# File 'lib/bitcoin/network/peer.rb', line 111

def support_witness?
  return false unless remote_version
  remote_version.services & Bitcoin::Message::SERVICE_FLAGS[:witness] > 0
end

#to_network_addrBitcoin::Message::NetworkAddr

generate Bitcoin::Message::NetworkAddr object from this peer info.



171
172
173
174
# File 'lib/bitcoin/network/peer.rb', line 171

def to_network_addr
  v = remote_version
  Bitcoin::Message::NetworkAddr.new(ip: host, port: port, services: v.services, time: v.timestamp)
end

#unbindObject



160
161
162
# File 'lib/bitcoin/network/peer.rb', line 160

def unbind
  pool.handle_close_peer(self)
end