ciri-p2p 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +15 -0
  5. data/.vscode/launch.json +90 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +65 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +45 -0
  11. data/Rakefile +6 -0
  12. data/bin/bundle +105 -0
  13. data/bin/console +14 -0
  14. data/bin/htmldiff +29 -0
  15. data/bin/ldiff +29 -0
  16. data/bin/rake +29 -0
  17. data/bin/rspec +29 -0
  18. data/bin/setup +8 -0
  19. data/ciri-p2p.gemspec +37 -0
  20. data/lib/ciri/p2p.rb +7 -0
  21. data/lib/ciri/p2p/address.rb +51 -0
  22. data/lib/ciri/p2p/dial_scheduler.rb +73 -0
  23. data/lib/ciri/p2p/dialer.rb +55 -0
  24. data/lib/ciri/p2p/discovery/protocol.rb +237 -0
  25. data/lib/ciri/p2p/discovery/service.rb +255 -0
  26. data/lib/ciri/p2p/errors.rb +36 -0
  27. data/lib/ciri/p2p/kad.rb +301 -0
  28. data/lib/ciri/p2p/network_state.rb +223 -0
  29. data/lib/ciri/p2p/node.rb +96 -0
  30. data/lib/ciri/p2p/peer.rb +151 -0
  31. data/lib/ciri/p2p/peer_store.rb +183 -0
  32. data/lib/ciri/p2p/protocol.rb +62 -0
  33. data/lib/ciri/p2p/protocol_context.rb +54 -0
  34. data/lib/ciri/p2p/protocol_io.rb +65 -0
  35. data/lib/ciri/p2p/rlpx.rb +29 -0
  36. data/lib/ciri/p2p/rlpx/connection.rb +182 -0
  37. data/lib/ciri/p2p/rlpx/encryption_handshake.rb +143 -0
  38. data/lib/ciri/p2p/rlpx/errors.rb +34 -0
  39. data/lib/ciri/p2p/rlpx/frame_io.rb +229 -0
  40. data/lib/ciri/p2p/rlpx/message.rb +45 -0
  41. data/lib/ciri/p2p/rlpx/protocol_handshake.rb +56 -0
  42. data/lib/ciri/p2p/rlpx/protocol_messages.rb +71 -0
  43. data/lib/ciri/p2p/rlpx/secrets.rb +49 -0
  44. data/lib/ciri/p2p/server.rb +159 -0
  45. data/lib/ciri/p2p/version.rb +5 -0
  46. metadata +229 -0
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 by Jiang Jinyang <jjyruby@gmail.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require 'ciri/rlp/serializable'
25
+
26
+ module Ciri
27
+ module P2P
28
+ module RLPX
29
+
30
+ class Cap
31
+ include Ciri::RLP::Serializable
32
+
33
+ schema(
34
+ name: RLP::Bytes,
35
+ version: Integer
36
+ )
37
+ end
38
+
39
+ # handle protocol handshake
40
+ class ProtocolHandshake
41
+ include Ciri::RLP::Serializable
42
+
43
+ schema(
44
+ version: Integer,
45
+ name: RLP::Bytes,
46
+ caps: [Cap],
47
+ listen_port: Integer,
48
+ id: RLP::Bytes
49
+ )
50
+ default_data(listen_port: 0)
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 by Jiang Jinyang <jjyruby@gmail.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ require 'ciri/key'
25
+ require 'ciri/rlp/serializable'
26
+
27
+ module Ciri
28
+ module P2P
29
+ module RLPX
30
+ # RLPX protocol code
31
+ module Code
32
+ HANDSHAKE = 0x00
33
+ DISCONNECT = 0x01
34
+ PING = 0x02
35
+ PONG = 0x03
36
+ end
37
+
38
+ BASE_PROTOCOL_VERSION = 5
39
+ BASE_PROTOCOL_LENGTH = 16
40
+ BASE_PROTOCOL_MAX_MSG_SIZE = 2 * 1024
41
+ SNAPPY_PROTOCOL_VERSION = 5
42
+
43
+ ### messages
44
+
45
+ class AuthMsgV4
46
+ include Ciri::RLP::Serializable
47
+
48
+ schema(
49
+ signature: RLP::Bytes,
50
+ initiator_pubkey: RLP::Bytes,
51
+ nonce: RLP::Bytes,
52
+ version: Integer
53
+ )
54
+
55
+ # keep this field let client known how to format(plain or eip8)
56
+ attr_accessor :got_plain
57
+ end
58
+
59
+ class AuthRespV4
60
+ include Ciri::RLP::Serializable
61
+
62
+ schema(
63
+ random_pubkey: RLP::Bytes,
64
+ nonce: RLP::Bytes,
65
+ version: Integer
66
+ )
67
+ end
68
+ end
69
+ end
70
+ end
71
+
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 by Jiang Jinyang <jjyruby@gmail.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+
24
+ module Ciri
25
+ module P2P
26
+ module RLPX
27
+
28
+ # class used to store rplx protocol secrets
29
+ class Secrets
30
+ attr_reader :remote_id, :aes, :mac
31
+ attr_accessor :egress_mac, :ingress_mac
32
+
33
+ def initialize(remote_id: nil, aes:, mac:)
34
+ @remote_id = remote_id
35
+ @aes = aes
36
+ @mac = mac
37
+ end
38
+
39
+ def ==(other)
40
+ self.class == other.class &&
41
+ remote_id == other.remote &&
42
+ aes == other.aes &&
43
+ mac == other.mac
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ # Copyright (c) 2018 by Jiang Jinyang <jjyruby@gmail.com>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+
24
+
25
+ require 'async'
26
+ require 'async/io'
27
+ require 'async/io/tcp_socket'
28
+ require 'forwardable'
29
+ require 'ciri/utils/logger'
30
+ require_relative 'rlpx/connection'
31
+ require_relative 'rlpx/protocol_handshake'
32
+ require_relative 'errors'
33
+ require_relative 'peer'
34
+ require_relative 'network_state'
35
+ require_relative 'dialer'
36
+ require_relative 'discovery/service'
37
+ require_relative 'dial_scheduler'
38
+
39
+ module Ciri
40
+ module P2P
41
+
42
+ # P2P Server
43
+ # maintain connection, node discovery, rlpx handshake
44
+ class Server
45
+ include Utils::Logger
46
+ include RLPX
47
+ extend Forwardable
48
+
49
+ DEFAULT_MAX_PENDING_PEERS = 50
50
+ DEFAULT_DIAL_RATIO = 3
51
+
52
+ attr_reader :handshake, :dial_scheduler, :dialer, :local_address, :tcp_port
53
+
54
+ def_delegators :@network_state, :disconnect_all
55
+
56
+ def initialize(private_key:, protocols:, bootnodes: [],
57
+ node_name: 'Ciri', host: '127.0.0.1',
58
+ tcp_port: 33033, udp_port: 33033,
59
+ max_outgoing: 10, max_incoming:10,
60
+ ping_interval_secs: 15,
61
+ discovery_interval_secs: 15,
62
+ dial_outgoing_interval_secs: 25)
63
+ @private_key = private_key
64
+ @node_name = node_name
65
+ # prepare handshake information
66
+ @local_node_id = NodeID.new(@private_key)
67
+ caps = protocols.map do |protocol|
68
+ Cap.new(name: protocol.name, version: protocol.version)
69
+ end
70
+ @handshake = ProtocolHandshake.new(version: BASE_PROTOCOL_VERSION, name: @node_name, id: @local_node_id.id, caps: caps)
71
+ @host = host
72
+ @tcp_port = tcp_port
73
+ @udp_port = udp_port
74
+ @dialer = Dialer.new(private_key: private_key, handshake: @handshake)
75
+ @peer_store = PeerStore.new
76
+ @network_state = NetworkState.new(
77
+ protocols: protocols,
78
+ peer_store: @peer_store,
79
+ local_node_id: @local_node_id,
80
+ max_incoming: max_incoming,
81
+ max_outgoing: max_outgoing,
82
+ ping_interval_secs: ping_interval_secs)
83
+ @bootnodes = bootnodes
84
+ @discovery_interval_secs = discovery_interval_secs
85
+ @dial_outgoing_interval_secs = dial_outgoing_interval_secs
86
+ end
87
+
88
+ def udp_port
89
+ @discovery_service&.udp_port || @udp_port
90
+ end
91
+
92
+ def to_node
93
+ address = Address.new(ip: @host, tcp_port: tcp_port, udp_port: udp_port)
94
+ Node.new(node_id: @local_node_id, addresses: [address])
95
+ end
96
+
97
+ # return reactor to wait
98
+ def run
99
+ # setup bootnodes
100
+ @bootnodes.each do |node|
101
+ @peer_store.add_bootnode(node)
102
+ end
103
+
104
+ # start server and services
105
+ Async::Reactor.run do |task|
106
+ # initialize protocols
107
+ @network_state.initialize_protocols
108
+ # wait sub tasks
109
+ task.async do
110
+ task.async do
111
+ # Wait for server started listen
112
+ # we use listened port to start DiscoveryService to allow 0 port
113
+ task.sleep(0.5) until @local_address
114
+
115
+ # start discovery service
116
+ @discovery_service = Discovery::Service.new(
117
+ peer_store: @peer_store,
118
+ private_key: @private_key,
119
+ host: @host, udp_port: @udp_port, tcp_port: @tcp_port,
120
+ discovery_interval_secs: @discovery_interval_secs)
121
+ task.async { @discovery_service.run }
122
+
123
+ # start dial outgoing nodes
124
+ @dial_scheduler = DialScheduler.new(
125
+ @network_state,
126
+ @dialer,
127
+ dial_outgoing_interval_secs: @dial_outgoing_interval_secs)
128
+ task.async {@dial_scheduler.run}
129
+ end
130
+ task.async {start_listen}
131
+ end.wait
132
+ end
133
+ end
134
+
135
+ # start listen and accept clients
136
+ def start_listen(task: Async::Task.current)
137
+ endpoint = Async::IO::Endpoint.tcp(@host, @tcp_port)
138
+ endpoint.bind do |socket|
139
+ @local_address = socket.local_address
140
+ info("start accept connections -- listen on #{@local_address.getnameinfo.join(":")}")
141
+ # update tcp_port if it is 0
142
+ if @tcp_port.zero?
143
+ @tcp_port = @local_address.ip_port
144
+ end
145
+ socket.listen(Socket::SOMAXCONN)
146
+ loop do
147
+ client, addrinfo = socket.accept
148
+ c = Connection.new(client)
149
+ c.encryption_handshake!(private_key: @private_key)
150
+ remote_handshake = c.protocol_handshake!(handshake)
151
+ @network_state.new_peer_connected(c, remote_handshake, way_for_connection: Peer::INCOMING)
152
+ end
153
+ end
154
+ end
155
+
156
+ end
157
+ end
158
+ end
159
+
@@ -0,0 +1,5 @@
1
+ module Ciri
2
+ module P2p
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,229 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ciri-p2p
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - jjy
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-11-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ciri-utils
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: ciri-rlp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: ciri-crypto
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: ciri-common
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: async
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.10.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.10.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: async-io
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.15.5
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.15.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: snappy
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.0.17
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.0.17
111
+ - !ruby/object:Gem::Dependency
112
+ name: bundler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.16'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.16'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '10.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '10.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.0'
153
+ description: ciri-p2p is a DevP2P implementation, we also seek to implement LibP2P
154
+ components upon ciri-p2p codebase in the future.
155
+ email:
156
+ - jjyruby@gmail.com
157
+ executables: []
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - ".gitignore"
162
+ - ".rspec"
163
+ - ".travis.yml"
164
+ - ".vscode/launch.json"
165
+ - CODE_OF_CONDUCT.md
166
+ - Gemfile
167
+ - Gemfile.lock
168
+ - LICENSE.txt
169
+ - README.md
170
+ - Rakefile
171
+ - bin/bundle
172
+ - bin/console
173
+ - bin/htmldiff
174
+ - bin/ldiff
175
+ - bin/rake
176
+ - bin/rspec
177
+ - bin/setup
178
+ - ciri-p2p.gemspec
179
+ - lib/ciri/p2p.rb
180
+ - lib/ciri/p2p/address.rb
181
+ - lib/ciri/p2p/dial_scheduler.rb
182
+ - lib/ciri/p2p/dialer.rb
183
+ - lib/ciri/p2p/discovery/protocol.rb
184
+ - lib/ciri/p2p/discovery/service.rb
185
+ - lib/ciri/p2p/errors.rb
186
+ - lib/ciri/p2p/kad.rb
187
+ - lib/ciri/p2p/network_state.rb
188
+ - lib/ciri/p2p/node.rb
189
+ - lib/ciri/p2p/peer.rb
190
+ - lib/ciri/p2p/peer_store.rb
191
+ - lib/ciri/p2p/protocol.rb
192
+ - lib/ciri/p2p/protocol_context.rb
193
+ - lib/ciri/p2p/protocol_io.rb
194
+ - lib/ciri/p2p/rlpx.rb
195
+ - lib/ciri/p2p/rlpx/connection.rb
196
+ - lib/ciri/p2p/rlpx/encryption_handshake.rb
197
+ - lib/ciri/p2p/rlpx/errors.rb
198
+ - lib/ciri/p2p/rlpx/frame_io.rb
199
+ - lib/ciri/p2p/rlpx/message.rb
200
+ - lib/ciri/p2p/rlpx/protocol_handshake.rb
201
+ - lib/ciri/p2p/rlpx/protocol_messages.rb
202
+ - lib/ciri/p2p/rlpx/secrets.rb
203
+ - lib/ciri/p2p/server.rb
204
+ - lib/ciri/p2p/version.rb
205
+ homepage: https://github.com/ciri-ethereum/ciri-p2p
206
+ licenses:
207
+ - MIT
208
+ metadata: {}
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ requirements: []
224
+ rubyforge_project:
225
+ rubygems_version: 2.7.6
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: P2P network implementation for Ciri Ethereum.
229
+ test_files: []