devp2p 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,9 +20,8 @@ module DEVp2p
20
20
  # The default implementation of `command.receive` calls callbacks which can
21
21
  # be registered in a list which is available as: `protocol.receive_X_callbacks`.
22
22
  #
23
- class BaseProtocol
24
- include Celluloid
25
- include Control
23
+ class Protocol
24
+ include Concurrent::Async
26
25
 
27
26
  extend Configurable
28
27
  add_config(
@@ -41,28 +40,31 @@ module DEVp2p
41
40
  @peer = peer
42
41
  @service = service
43
42
 
44
- initialize_control
43
+ @stopped = false
45
44
 
46
45
  setup
47
46
  end
48
47
 
49
48
  def start
50
- logger.debug 'starting', proto: Actor.current
51
- service.on_wire_protocol_start Actor.current
52
- super
49
+ logger.debug 'starting', proto: self
50
+ service.async.on_wire_protocol_start self
51
+ rescue
52
+ puts $!
53
+ puts $!.backtrace[0,10].join("\n")
53
54
  end
54
55
 
55
56
  def stop
56
- logger.debug 'stopping', proto: Actor.current
57
- service.on_wire_protocol_stop Actor.current
57
+ logger.debug 'stopping', proto: self
58
+ service.async.on_wire_protocol_stop self
58
59
 
59
- super
60
-
61
- terminate
60
+ @stopped = true
61
+ rescue
62
+ puts $!
63
+ puts $!.backtrace[0,10].join("\n")
62
64
  end
63
65
 
64
- def _run
65
- # pass
66
+ def stopped?
67
+ @stopped
66
68
  end
67
69
 
68
70
  def receive_packet(packet)
@@ -75,7 +77,7 @@ module DEVp2p
75
77
  end
76
78
 
77
79
  def send_packet(packet)
78
- peer.send_packet packet
80
+ peer.async.send_packet packet
79
81
  end
80
82
 
81
83
  def to_s
@@ -98,14 +100,14 @@ module DEVp2p
98
100
 
99
101
  raise DuplicatedCommand unless klasses.map(&:cmd_id).uniq.size == klasses.size
100
102
 
101
- proto = Actor.current
103
+ proto = self
102
104
 
103
105
  klasses.each do |klass|
104
106
  instance = klass.new
105
107
 
106
108
  # decode rlp, create hash, call receive
107
109
  receive = lambda do |packet|
108
- raise ArgumentError unless packet.is_a?(Packet)
110
+ raise ArgumentError, "packet is not a Packet: #{packet.inspect}" unless packet.is_a?(Packet)
109
111
  instance.receive proto, klass.decode_payload(packet.payload)
110
112
  end
111
113
 
@@ -0,0 +1,50 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ module DEVp2p
4
+
5
+ class Service
6
+ include Concurrent::Async
7
+
8
+ extend Configurable
9
+ add_config(
10
+ name: '',
11
+ default_config: {},
12
+ required_services: []
13
+ )
14
+
15
+ class <<self
16
+ def register_with_app(app)
17
+ app.register_service self, app
18
+ end
19
+ end
20
+
21
+ attr :app, :config
22
+
23
+ def initialize(app)
24
+ super()
25
+
26
+ @app = app
27
+ @config = app.config.reverse_merge(default_config)
28
+
29
+ available_services = app.services.each_value.map(&:class)
30
+ required_services.each do |r|
31
+ raise MissingRequiredServiceError, "require service #{r}" unless available_services.include?(r)
32
+ end
33
+ end
34
+
35
+ def start
36
+ raise NotImplemented
37
+ end
38
+
39
+ def stop
40
+ raise NotImplemented
41
+ end
42
+
43
+ def to_s
44
+ "<Service #{name}##{object_id}>"
45
+ end
46
+ alias inspect to_s
47
+
48
+ end
49
+
50
+ end
@@ -1,8 +1,7 @@
1
1
  # -*- encoding : ascii-8bit -*-
2
2
 
3
- ##
4
- # A naive synchronized queue for Celluloid actors.
5
- #
3
+ require 'thread'
4
+
6
5
  class SyncQueue
7
6
 
8
7
  attr :queue, :max_size
@@ -12,69 +11,83 @@ class SyncQueue
12
11
  @num_waiting = 0
13
12
 
14
13
  @max_size = max_size
15
- @cond_full = Celluloid::Condition.new
16
- @cond_empty = Celluloid::Condition.new
14
+
15
+ @mutex = Mutex.new
16
+ @cond_full = ConditionVariable.new
17
+ @cond_empty = ConditionVariable.new
17
18
  end
18
19
 
19
20
  def enq(obj, non_block=false)
20
- loop do
21
- if full?
22
- if non_block
23
- raise ThreadError, 'queue full'
24
- else
25
- begin
26
- @num_waiting += 1
27
- @cond_full.wait
28
- ensure
29
- @num_waiting -= 1
21
+ Thread.handle_interrupt(StandardError => :on_blocking) do
22
+ loop do
23
+ @mutex.synchronize do
24
+ if full?
25
+ if non_block
26
+ raise ThreadError, 'queue full'
27
+ else
28
+ begin
29
+ @num_waiting += 1
30
+ @cond_full.wait @mutex
31
+ ensure
32
+ @num_waiting -= 1
33
+ end
34
+ end
35
+ else
36
+ @queue.push obj
37
+ @cond_empty.signal
38
+ return obj
30
39
  end
31
40
  end
32
- else
33
- @queue.push obj
34
- @cond_empty.signal
35
- return obj
36
41
  end
37
42
  end
38
43
  end
39
44
  alias << enq
40
45
 
41
46
  def deq(non_block=false)
42
- loop do
43
- if empty?
44
- if non_block
45
- raise ThreadError, 'queue empty'
46
- else
47
- begin
48
- @num_waiting += 1
49
- @cond_empty.wait
50
- ensure
51
- @num_waiting -= 1
47
+ Thread.handle_interrupt(StandardError => :on_blocking) do
48
+ loop do
49
+ @mutex.synchronize do
50
+ if empty?
51
+ if non_block
52
+ raise ThreadError, 'queue empty'
53
+ else
54
+ begin
55
+ @num_waiting += 1
56
+ @cond_empty.wait @mutex
57
+ ensure
58
+ @num_waiting -= 1
59
+ end
60
+ end
61
+ else
62
+ obj = @queue.shift
63
+ @cond_full.signal
64
+ return obj
52
65
  end
53
66
  end
54
- else
55
- obj = @queue.shift
56
- @cond_full.signal
57
- return obj
58
67
  end
59
68
  end
60
69
  end
61
70
 
62
71
  # Same as pop except it will not remove the element from queue, just peek.
63
72
  def peek(non_block=false)
64
- loop do
65
- if empty?
66
- if non_block
67
- raise ThreadError, 'queue empty'
68
- else
69
- begin
70
- @num_waiting += 1
71
- @cond_empty.wait
72
- ensure
73
- @num_waiting -= 1
73
+ Thread.handle_interrupt(StandardError => :on_blocking) do
74
+ loop do
75
+ @mutex.synchronize do
76
+ if empty?
77
+ if non_block
78
+ raise ThreadError, 'queue empty'
79
+ else
80
+ begin
81
+ @num_waiting += 1
82
+ @cond_empty.wait @mutex
83
+ ensure
84
+ @num_waiting -= 1
85
+ end
86
+ end
87
+ else
88
+ return @queue[0]
74
89
  end
75
90
  end
76
- else
77
- return @queue[0]
78
91
  end
79
92
  end
80
93
  end
@@ -1,6 +1,7 @@
1
1
  # -*- encoding : ascii-8bit -*-
2
+
2
3
  module DEVp2p
3
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
4
5
 
5
6
  VersionString = begin
6
7
  git_describe_re = /^(?<version>v\d+\.\d+\.\d+)-(?<git>\d+-g[a-fA-F0-9]+(?:-dirty)?)$/
@@ -12,17 +12,17 @@ module DEVp2p
12
12
  # with instances of Peer and WiredService
13
13
  # WiredService.wire_protocol(Peer.new, WiredService.new)
14
14
  #
15
- class WiredService < BaseService
15
+ class WiredService < Service
16
16
  name 'wired'
17
17
 
18
18
  attr_accessor :wire_protocol
19
19
 
20
20
  def on_wire_protocol_start(proto)
21
- raise ArgumentError, "argument is not a protocol" unless proto.is_a?(BaseProtocol)
21
+ raise ArgumentError, "argument is not a protocol" unless proto.is_a?(::DEVp2p::Protocol)
22
22
  end
23
23
 
24
24
  def on_wire_protocol_stop(proto)
25
- raise ArgumentError, "argument is not a protocol" unless proto.is_a?(BaseProtocol)
25
+ raise ArgumentError, "argument is not a protocol" unless proto.is_a?(::DEVp2p::Protocol)
26
26
  end
27
27
 
28
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devp2p
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Xie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-19 00:00:00.000000000 Z
11
+ date: 2016-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -38,34 +38,6 @@ dependencies:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.1.2
41
- - !ruby/object:Gem::Dependency
42
- name: celluloid
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.17'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.17'
55
- - !ruby/object:Gem::Dependency
56
- name: celluloid-io
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 0.17.3
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 0.17.3
69
41
  - !ruby/object:Gem::Dependency
70
42
  name: digest-sha3
71
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +80,20 @@ dependencies:
108
80
  - - ">="
109
81
  - !ruby/object:Gem::Version
110
82
  version: 0.7.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: concurrent-ruby
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: rake
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -162,14 +148,10 @@ files:
162
148
  - LICENSE
163
149
  - README.md
164
150
  - lib/devp2p.rb
165
- - lib/devp2p/app_helper.rb
166
- - lib/devp2p/base_app.rb
167
- - lib/devp2p/base_protocol.rb
168
- - lib/devp2p/base_service.rb
151
+ - lib/devp2p/app.rb
169
152
  - lib/devp2p/command.rb
170
153
  - lib/devp2p/configurable.rb
171
154
  - lib/devp2p/connection_monitor.rb
172
- - lib/devp2p/control.rb
173
155
  - lib/devp2p/crypto.rb
174
156
  - lib/devp2p/crypto/ecc_x.rb
175
157
  - lib/devp2p/crypto/ecies.rb
@@ -194,7 +176,9 @@ files:
194
176
  - lib/devp2p/peer.rb
195
177
  - lib/devp2p/peer_errors.rb
196
178
  - lib/devp2p/peer_manager.rb
179
+ - lib/devp2p/protocol.rb
197
180
  - lib/devp2p/rlpx_session.rb
181
+ - lib/devp2p/service.rb
198
182
  - lib/devp2p/sync_queue.rb
199
183
  - lib/devp2p/utils.rb
200
184
  - lib/devp2p/version.rb
@@ -1,85 +0,0 @@
1
- # -*- encoding : ascii-8bit -*-
2
-
3
- module DEVp2p
4
- class AppHelper
5
-
6
- def run(app_class, service_class, num_nodes: 3, seed: 0, min_peers: 2, max_peers: 2, random_port: false)
7
- base_port = random_port ? SecureRandom.random_number(50000) + 10000 : 29870
8
-
9
- bootstrap_node_privkey = Crypto.mk_privkey "#{seed}:udp:0"
10
- bootstrap_node_pubkey = Crypto.privtopub bootstrap_node_privkey
11
- enode = Utils.host_port_pubkey_to_uri "0.0.0.0", base_port, bootstrap_node_pubkey
12
-
13
- services = [Discovery::Service, PeerManager]#, service_class]
14
-
15
- base_config = {}
16
- services.each {|s| Utils.update_config_with_defaults base_config, s.default_config }
17
-
18
- base_config[:discovery][:bootstrap_nodes] = [enode]
19
- base_config[:seed] = seed
20
- base_config[:base_port] = base_port
21
- base_config[:num_nodes] = num_nodes
22
- base_config[:min_peers] = min_peers
23
- base_config[:max_peers] = max_peers
24
-
25
- apps = []
26
- num_nodes.times do |node_num|
27
- app = create_app node_num, base_config, services, app_class
28
- apps.push app
29
- end
30
-
31
- serve_until_stopped apps
32
- end
33
-
34
- def create_app(node_num, config, services, app_class)
35
- num_nodes = config[:num_nodes]
36
- base_port = config[:base_port]
37
- seed = config[:seed]
38
- min_peers = config[:min_peers]
39
- max_peers = config[:max_peers]
40
-
41
- raise "invalid node_num" unless node_num < num_nodes
42
- #raise "invalid min/max peers" unless min_peers <= max_peers && max_peers < num_nodes
43
-
44
- config = Marshal.load Marshal.dump(config)
45
- config[:node_num] = node_num
46
-
47
- config[:node][:privkey_hex] = Utils.encode_hex Crypto.mk_privkey("#{seed}:udp:#{node_num}")
48
- config[:discovery][:listen_port] = base_port + node_num
49
- config[:p2p][:listen_port] = base_port + node_num
50
- config[:p2p][:min_peers] = [min_peers, 10].min
51
- config[:p2p][:max_peers] = max_peers
52
- config[:client_version_string] = "NODE#{node_num}"
53
-
54
- app = app_class.new config
55
-
56
- services.each do |service|
57
- raise "invalid service" unless service.instance_of?(Class) && service < BaseService
58
-
59
- if !app.config[:deactivated_services].include?(service.name)
60
- raise "service should not be active" if app.services.has_key?(service.name)
61
- service.register_with_app app
62
- raise "servier should be active" unless app.services.has_key?(service.name)
63
- end
64
- end
65
-
66
- app
67
- end
68
-
69
- def serve_until_stopped(apps)
70
- apps.each do |app|
71
- app.start
72
-
73
- if app.config[:post_app_start_callback]
74
- app.config[:post_app_start_callback].call(app)
75
- end
76
- end
77
-
78
- apps.each(&:join)
79
-
80
- # finally stop
81
- apps.each(&:stop)
82
- end
83
-
84
- end
85
- end