Commit cdce403c7d201692c963fe911f9e9a646391424e

Authored by Marius Hanne
1 parent 540865da27

ping/pong messages as defined in BIP31

Showing 4 changed files with 84 additions and 2 deletions Side-by-side Diff

lib/bitcoin/network/connection_handler.rb
... ... @@ -196,6 +196,14 @@
196 196 send_data(Protocol.pkt("getaddr", ""))
197 197 end
198 198  
  199 + # send +ping+ message
  200 + # TODO: wait for pong and disconnect if it doesn't arrive (and version is new enough)
  201 + def send_ping
  202 + nonce = rand(0xffffffff)
  203 + log.debug { "<< ping (#{nonce})" }
  204 + send_data(Protocol.ping_pkt(nonce))
  205 + end
  206 +
199 207 # ask for the genesis block
200 208 def get_genesis_block
201 209 log.info { "Asking for genesis block" }
... ... @@ -211,7 +219,22 @@
211 219 @started = Time.now
212 220 @node.notifiers[:connection].push([:connected, info])
213 221 @node.addrs << addr
214   - #send_getaddr
  222 + # send_getaddr
  223 + # EM.add_periodic_timer(15) { send_ping }
  224 + end
  225 +
  226 + # received +ping+ message with given +nonce+.
  227 + # send +pong+ message back, if +nonce+ is set.
  228 + # network versions <=60000 don't set the nonce and don't expect a pong.
  229 + def on_ping nonce
  230 + log.debug { ">> ping (#{nonce})" }
  231 + send_data(Protocol.pong_pkt(nonce)) if nonce
  232 + end
  233 +
  234 + # received +pong+ message with given +nonce+.
  235 + # TODO: see #send_ping
  236 + def on_pong nonce
  237 + log.debug { ">> pong (#{nonce})" }
215 238 end
216 239  
217 240 # begin handshake; send +version+ message
lib/bitcoin/protocol.rb
... ... @@ -16,7 +16,7 @@
16 16 autoload :Handler, 'bitcoin/protocol/handler'
17 17 autoload :Parser, 'bitcoin/protocol/parser'
18 18  
19   - VERSION = 31900
  19 + VERSION = 60001
20 20  
21 21 DNS_Seed = [ "bitseed.xf2.org", "bitseed.bitcoin.org.uk" ]
22 22 Uniq = rand(0xffffffffffffffff)
... ... @@ -71,6 +71,14 @@
71 71 def self.version_pkt(from_id, from, to, last_block=nil, time=nil, user_agent=nil)
72 72 payload = Protocol::Version.build_payload(from_id, from, to, last_block, time, user_agent)
73 73 pkt("version", payload)
  74 + end
  75 +
  76 + def self.ping_pkt(nonce = rand(0xffffffff))
  77 + pkt("ping", [nonce].pack("Q"))
  78 + end
  79 +
  80 + def self.pong_pkt(nonce)
  81 + pkt("pong", [nonce].pack("Q"))
74 82 end
75 83  
76 84 def self.verack_pkt
lib/bitcoin/protocol/parser.rb
... ... @@ -68,6 +68,8 @@
68 68 when 'verack'; @h.on_handshake_complete # nop
69 69 when 'version'; parse_version(payload)
70 70 when 'alert'; parse_alert(payload)
  71 + when 'ping'; @h.on_ping(payload.unpack("Q")[0])
  72 + when 'pong'; @h.on_pong(payload.unpack("Q")[0])
71 73 else
72 74 p ['unkown-packet', command, payload]
73 75 end
spec/bitcoin/protocol/ping_spec.rb
  1 +require_relative '../spec_helper.rb'
  2 +
  3 +describe 'Bitcoin::Protocol::Parser (ping/pong)' do
  4 +
  5 + class Ping_Handler < Bitcoin::Protocol::Handler
  6 + attr_reader :nonce
  7 + def on_ping(nonce)
  8 + @nonce = nonce
  9 + end
  10 + def on_pong(nonce)
  11 + @nonce = nonce
  12 + end
  13 + end
  14 +
  15 + before do
  16 + @parser = Bitcoin::Protocol::Parser.new( @handler = Ping_Handler.new )
  17 + end
  18 +
  19 + it 'parses ping without nonce' do
  20 + @parser.parse(Bitcoin::Protocol.pkt("ping", "") + "AAAA").should == "AAAA"
  21 + @handler.nonce.should == nil
  22 + end
  23 +
  24 + it 'parses ping with nonce' do
  25 + @parser.parse(Bitcoin::Protocol.pkt("ping", [12345].pack("Q")) + "AAAA").should == "AAAA"
  26 + @handler.nonce.should == 12345
  27 + end
  28 +
  29 + it 'builds ping without nonce' do
  30 + @parser.parse(Bitcoin::Protocol::ping_pkt)
  31 + @handler.nonce.should != nil
  32 + end
  33 +
  34 + it 'builds ping with nonce' do
  35 + @parser.parse(Bitcoin::Protocol::ping_pkt(12345))
  36 + @handler.nonce.should == 12345
  37 + end
  38 +
  39 + it 'parses pong' do
  40 + @parser.parse(Bitcoin::Protocol.pkt("pong", [12345].pack("Q")) + "AAAA").should == "AAAA"
  41 + @handler.nonce.should == 12345
  42 + end
  43 +
  44 + it 'builds pong' do
  45 + @parser.parse(Bitcoin::Protocol::pong_pkt(12345))
  46 + @handler.nonce.should == 12345
  47 + end
  48 +
  49 +end