devp2p 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a9119de12a32ac914f74a103d5544358404a241
4
- data.tar.gz: 1f7107a8432d2a9b7a74c676623eeeceec717f42
3
+ metadata.gz: 7da6641d9e8596c7a5ef84501b60dba802a38c7d
4
+ data.tar.gz: eb5ae074cca21812736d03f67949648242482b87
5
5
  SHA512:
6
- metadata.gz: 869067f4897deb649c694a535eedc8d5cee3a725625c3760a6a069f933cdb08c93d5d16141b9a10cdabba60238c472476e5f98c2a32dea4cddafeadd3d65046f
7
- data.tar.gz: 8340dc9d8f31803e250ecfc859a9397f9f84e70ad80513fc6874e6a4b825c78d8b777689bb286bbceb8ea934b97b0f037e53933483e8fdbc18ae16f032fa95de
6
+ metadata.gz: 2580541428dc68edea68859e888e235c940637fe2219759d35a58ba3256d96d7de364a343c74935bf714b7c4f54c8be3fc1291e0a6d099bf32df38973c0678c2
7
+ data.tar.gz: 95f168e5a41dc87646a55dbc794a0cb64984fc8e10aef647f7b94fa09820f1cc6645bdb6e1b6fa625925d618df1b436a99aabc8a8d07611ca1f28f32a739a634
@@ -1,16 +1,9 @@
1
1
  # -*- encoding : ascii-8bit -*-
2
2
 
3
+ require 'concurrent'
3
4
  require 'block_logger'
4
- require 'celluloid/io'
5
-
6
5
  require 'rlp'
7
6
 
8
- #Celluloid.exception_handler do |ex|
9
- # puts "!!!!! Exception raised in celluloid actor:"
10
- # puts ex
11
- # puts ex.backtrace[0,20].join("\n")
12
- #end
13
-
14
7
  module DEVp2p
15
8
  Logger = BlockLogger
16
9
 
@@ -22,36 +15,28 @@ end
22
15
 
23
16
  require 'devp2p/version'
24
17
 
25
- require 'devp2p/configurable'
26
- require 'devp2p/utils'
27
18
  require 'devp2p/exception'
19
+ require 'devp2p/crypto'
20
+ require 'devp2p/utils'
21
+ require 'devp2p/configurable'
28
22
 
29
- require 'devp2p/control'
30
- require 'devp2p/base_service'
23
+ require 'devp2p/app'
24
+ require 'devp2p/service'
31
25
  require 'devp2p/wired_service'
32
26
 
33
- require 'devp2p/kademlia'
34
- require 'devp2p/discovery'
35
-
36
27
  require 'devp2p/sync_queue'
37
-
38
- require 'devp2p/packet'
39
28
  require 'devp2p/frame'
29
+ require 'devp2p/packet'
40
30
  require 'devp2p/multiplexer'
41
-
42
- require 'devp2p/crypto'
43
- require 'devp2p/rlpx_session'
44
31
  require 'devp2p/multiplexed_session'
32
+ require 'devp2p/rlpx_session'
45
33
 
46
- require 'devp2p/command'
47
- require 'devp2p/base_protocol'
34
+ require 'devp2p/kademlia'
35
+ require 'devp2p/discovery'
48
36
  require 'devp2p/connection_monitor'
37
+ require 'devp2p/command'
38
+ require 'devp2p/protocol'
49
39
  require 'devp2p/p2p_protocol'
50
-
51
- require 'devp2p/peer'
52
- require 'devp2p/peer_errors'
53
40
  require 'devp2p/peer_manager'
54
-
55
- require 'devp2p/base_app'
56
- require 'devp2p/app_helper'
57
-
41
+ require 'devp2p/peer_errors'
42
+ require 'devp2p/peer'
@@ -0,0 +1,70 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+ require 'hashie'
3
+
4
+ module DEVp2p
5
+ class App
6
+ include Concurrent::Async
7
+
8
+ extend Configurable
9
+ add_config(
10
+ default_config: {
11
+ client_version_string: "ruby-devp2p #{VersionString}",
12
+ deactivated_services: []
13
+ }
14
+ )
15
+
16
+ attr :config, :services
17
+
18
+ def initialize(config=default_config)
19
+ super()
20
+
21
+ @config = Hashie::Mash.new(default_config).merge(config)
22
+ @registry = {}
23
+ @services = Hashie::Mash.new
24
+ end
25
+
26
+ def register_service(klass, *args)
27
+ raise ArgumentError, "service #{klass.name} already registered" if services.has_key?(klass.name)
28
+
29
+ logger.info "registering service", service: klass.name
30
+ @registry[klass.name] = [klass, args]
31
+ services[klass.name] = klass.new(*args)
32
+ end
33
+
34
+ def deregister_service(klass)
35
+ raise ArgumentError, "service #{klass.name} not registered" unless services.has_key?(klass.name)
36
+
37
+ logger.info "deregistering service", service: klass.name
38
+ services[klass.name].async.stop
39
+ services.delete klass.name
40
+ @registry.delete klass.name
41
+ end
42
+
43
+ def start
44
+ @registry.each do |name, (klass, args)|
45
+ services[name] ||= klass.new(*args)
46
+ services[name].async.start
47
+ end
48
+ rescue
49
+ puts $!
50
+ puts $!.backtrace[0,10].join("\n")
51
+ end
52
+
53
+ def stop
54
+ services.keys.each do |name|
55
+ services[name].async.stop
56
+ services.delete name
57
+ end
58
+ rescue
59
+ puts $!
60
+ puts $!.backtrace[0,10].join("\n")
61
+ end
62
+
63
+ private
64
+
65
+ def logger
66
+ @logger ||= Logger.new 'app'
67
+ end
68
+
69
+ end
70
+ end
@@ -64,7 +64,7 @@ module DEVp2p
64
64
  # optionally implement create
65
65
  def create(proto, *args)
66
66
  options = args.last.is_a?(Hash) ? args.pop : {}
67
- raise ArgumentError, "proto #{proto} must be protocol" unless proto.is_a?(BaseProtocol)
67
+ raise ArgumentError, "proto #{proto} must be protocol" unless proto.is_a?(Protocol)
68
68
  raise ArgumentError, "command structure mismatch" if !options.empty? && structure.instance_of?(RLP::Sedes::CountableList)
69
69
  options.empty? ? args : options
70
70
  end
@@ -6,7 +6,7 @@ module DEVp2p
6
6
  # monitors the connection by sending pings and checking pongs
7
7
  #
8
8
  class ConnectionMonitor
9
- include Celluloid
9
+ include Concurrent::Async
10
10
 
11
11
  def initialize(proto)
12
12
  @proto = proto
@@ -28,8 +28,10 @@ module DEVp2p
28
28
  }
29
29
  @proto.receive_pong_callbacks.push(track_response)
30
30
 
31
- monitor = Actor.current
32
- @proto.receive_hello_callbacks.push(->(p, **kwargs) { monitor.start })
31
+ monitor = self
32
+ # FIXME: sleep 1 to make sure ConnectionMonitor start after connection of
33
+ # other protocols like ETHProtocol
34
+ @proto.receive_hello_callbacks.push(->(p, **kwargs) { sleep 1; monitor.start })
33
35
  end
34
36
 
35
37
  def latency(num_samples=@max_samples)
@@ -38,38 +40,42 @@ module DEVp2p
38
40
  (0...num_samples).map {|i| @samples[i] }.reduce(0, &:+)
39
41
  end
40
42
 
41
- def run
42
- logger.debug 'started', monitor: Actor.current
43
- loop do
44
- logger.debug 'pinging', monitor: Actor.current
45
- @proto.send_ping
43
+ def start
44
+ logger.debug 'started', monitor: self
46
45
 
47
- now = @last_request = Time.now
48
- sleep @ping_interval
46
+ logger.debug 'pinging', monitor: self
47
+ @proto.async.send_ping
48
+ now = @last_request = Time.now
49
+
50
+ @task = Concurrent::TimerTask.new(execution_interval: @ping_interval) do
49
51
  logger.debug('latency', peer: @proto, latency: ("%.3f" % latency))
50
52
 
51
53
  if now - @last_response > @response_delay_threshold
52
- logger.debug "unresponsive_peer", monitor: Actor.current
53
- @proto.peer.report_error 'not responding to ping'
54
- @proto.stop
55
- terminate
54
+ logger.debug "unresponsive_peer", monitor: self
55
+ @proto.peer.async.report_error 'not responding to ping'
56
+ @proto.async.stop
56
57
  end
57
- end
58
- end
59
58
 
60
- def start
61
- async.run
59
+ logger.debug 'pinging', monitor: self
60
+ @proto.async.send_ping
61
+ now = @last_request = Time.now
62
+ end
63
+ @task.execute
64
+ rescue
65
+ puts $!
66
+ puts $!.backtrace[0,10].join("\n")
62
67
  end
63
68
 
64
69
  def stop
65
- logger.debug 'stopped', monitor: Actor.current
66
- terminate
70
+ logger.debug 'stopped', monitor: self
71
+ @task.shutdown
72
+ @task = nil
67
73
  end
68
74
 
69
75
  private
70
76
 
71
77
  def logger
72
- @logger ||= Logger.new("#{@proto.peer.config[:p2p][:listen_port]}.p2p.ctxmonitor.#{object_id}")
78
+ @logger ||= Logger.new("p2p.ctxmonitor")
73
79
  end
74
80
 
75
81
  end
@@ -1,3 +1,4 @@
1
+ # -*- encoding : ascii-8bit -*-
1
2
  ##
2
3
  # # Node Discovery Protocol
3
4
  #
@@ -110,7 +111,6 @@
110
111
  # }
111
112
  #
112
113
 
113
-
114
114
  require 'devp2p/discovery/address'
115
115
  require 'devp2p/discovery/node'
116
116
  require 'devp2p/discovery/kademlia_protocol_adapter'
@@ -173,7 +173,7 @@ module DEVp2p
173
173
  get_node(nodeid, address) unless @nodes.has_key?(nodeid)
174
174
  send cmd, nodeid, payload, mdc
175
175
  rescue
176
- logger.error 'invalid message', error: $!
176
+ logger.error 'invalid message', error: $!, from: address
177
177
  end
178
178
 
179
179
  def send_message(node, message)
@@ -319,7 +319,7 @@ module DEVp2p
319
319
  private
320
320
 
321
321
  def logger
322
- @logger ||= Logger.new("#{udp_port}.p2p.discovery").tap {|l| l.level = :info }
322
+ @logger ||= Logger.new("p2p.discovery").tap {|l| l.level = :info }
323
323
  end
324
324
 
325
325
  def encode_cmd_id(cmd_id)
@@ -3,12 +3,82 @@
3
3
  module DEVp2p
4
4
  module Discovery
5
5
 
6
- ##
7
- # Persist the list of known nodes with their reputation.
8
- #
9
- class Service < BaseService
10
- include Celluloid::IO
6
+ class Receiver
7
+ include Concurrent::Async
11
8
 
9
+ def initialize(service, socket)
10
+ super()
11
+
12
+ @service = service
13
+ @socket = socket
14
+
15
+ @stopped = false
16
+ end
17
+
18
+ def start
19
+ maxlen = Multiplexer.max_window_size * 2
20
+
21
+ loop do
22
+ break if @stopped || @socket.closed?
23
+
24
+ message, info = @socket.recvfrom maxlen
25
+ handle_packet message, info[3], info[1]
26
+ end
27
+ rescue
28
+ puts $!
29
+ puts $!.backtrace[0,10].join("\n")
30
+ end
31
+
32
+ def stop
33
+ @stopped = true
34
+ end
35
+
36
+ def handle_packet(message, ip, port)
37
+ logger.debug "handling packet", ip: ip, port: port, size: message.size
38
+ @service.async.receive_message Address.new(ip, port), message
39
+ end
40
+
41
+ private
42
+
43
+ def logger
44
+ @logger ||= Logger.new "p2p.discovery"
45
+ end
46
+ end
47
+
48
+ class Sender
49
+ include Concurrent::Async
50
+
51
+ def initialize(service, socket)
52
+ super()
53
+
54
+ @service = service
55
+ @socket = socket
56
+
57
+ @stopped = false
58
+ end
59
+
60
+ def start
61
+ # do nothing
62
+ end
63
+
64
+ def send_message(address, message)
65
+ raise ArgumentError, 'address must be Address' unless address.instance_of?(Address)
66
+ logger.debug "sending", size: message.size, to: address
67
+
68
+ @socket.send message, 0, address.ip, address.udp_port
69
+ rescue
70
+ puts $!
71
+ puts $!.backtrace[0,10].join("\n")
72
+ end
73
+
74
+ private
75
+
76
+ def logger
77
+ @logger ||= Logger.new "p2p.discovery"
78
+ end
79
+ end
80
+
81
+ class Service < ::DEVp2p::Service
12
82
  name 'discovery'
13
83
 
14
84
  default_config(
@@ -27,33 +97,8 @@ module DEVp2p
27
97
  super(app)
28
98
  logger.info "Discovery service init"
29
99
 
30
- @server = nil # will be UDPSocket
31
- @protocol = Protocol.new app, Actor.current
32
- end
33
-
34
- def address
35
- ip = @app.config[:discovery][:listen_host]
36
- port = @app.config[:discovery][:listen_port]
37
- Address.new ip, port
38
- end
39
-
40
- def send_message(address, message)
41
- raise ArgumentError, 'address must be Address' unless address.instance_of?(Address)
42
- logger.debug "sending", size: message.size, to: address
43
-
44
- begin
45
- @server.send message, 0, address.ip, address.udp_port
46
- rescue
47
- # should never reach here? udp has no connection!
48
- logger.error "udp write error", error: $!
49
- logger.error "waiting for recovery"
50
- sleep 5
51
- end
52
- end
53
-
54
- def receive_message(address, message)
55
- raise ArgumentError, 'address must be Address' unless address.instance_of?(Address)
56
- @protocol.receive_message address, message
100
+ @socket = nil
101
+ @protocol = Protocol.new app, self
57
102
  end
58
103
 
59
104
  def start
@@ -64,38 +109,52 @@ module DEVp2p
64
109
 
65
110
  logger.info "starting udp listener", port: port, host: ip
66
111
 
67
- @server = UDPSocket.new
68
- @server.bind ip, port
112
+ @socket = UDPSocket.new
113
+ @socket.bind ip, port
69
114
 
70
- super
115
+ @receiver = Receiver.new self, @socket
116
+ @sender = Sender.new self, @socket
117
+ @receiver.async.start
118
+ @sender.async.start
71
119
 
72
120
  nodes = @app.config[:discovery][:bootstrap_nodes] || []
73
121
  @protocol.bootstrap( nodes.map {|x| Node.from_uri(x) } )
122
+ rescue
123
+ puts $!
124
+ puts $!.backtrace[0,10].join("\n")
74
125
  end
75
126
 
76
127
  def stop
77
128
  logger.info "stopping discovery"
78
- super
129
+
130
+ @socket.close if @socket
131
+ @sender.async.stop if @sender
132
+ @receiver.async.stop if @receiver
133
+
134
+ @socket = nil
135
+ @sender = nil
136
+ @receiver = nil
79
137
  end
80
138
 
81
- private
139
+ def address
140
+ ip = @app.config[:discovery][:listen_host]
141
+ port = @app.config[:discovery][:listen_port]
142
+ Address.new ip, port
143
+ end
82
144
 
83
- def logger
84
- @logger ||= Logger.new "#{@app.config[:discovery][:listen_port]}.p2p.discovery"
145
+ def receive_message(address, message)
146
+ raise ArgumentError, 'address must be Address' unless address.instance_of?(Address)
147
+ @protocol.receive_message address, message
85
148
  end
86
149
 
87
- def _run
88
- maxlen = Multiplexer.max_window_size * 2
89
- loop do
90
- break if stopped?
91
- message, info = @server.recvfrom maxlen
92
- async.handle_packet message, info[3], info[1]
93
- end
150
+ def send_message(address, message)
151
+ @sender.async.send_message address, message
94
152
  end
95
153
 
96
- def handle_packet(message, ip, port)
97
- logger.debug "handling packet", ip: ip, port: port, size: message.size
98
- receive_message Address.new(ip, port), message
154
+ private
155
+
156
+ def logger
157
+ @logger ||= Logger.new "p2p.discovery"
99
158
  end
100
159
 
101
160
  end