ciri-p2p 0.1.0 → 0.2.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
  SHA256:
3
- metadata.gz: 2d4f5def844a74637c9a5aae3a6716df8d35743bc165f818f166b3ba5b645a97
4
- data.tar.gz: 7fa69fc607c4bed9a5e1d169743b0b4b4f9866141175648094fe7e14aee38e7c
3
+ metadata.gz: 84a78196ee2a9a850e3f893c8f3f7a4a30eae83eb9cde69537020215723b9a8e
4
+ data.tar.gz: '09e75872015ea1b557150db5650f4ef2ccd7bcd180b6fbfa2caa78eae705a769'
5
5
  SHA512:
6
- metadata.gz: 633de9a2b3118aa103eafab18167c12a45c4f3852fa7f5c35e52667a92ced44bde8cdc4b843aabf4a9b441c5362ec6e8400e2aac8d98599fddbd44791fed1370
7
- data.tar.gz: a9e761a941672630419300fccce12dc1a0726cf8db35c2a7961ac94c138d4265824af02149c672580423c92c661d3595dcc9588e75c6bf47a1ab106fb56a9244
6
+ metadata.gz: adb6135d935ee3ec9e4aa77c65a0aa44d741481acc44b30d6c880f6a9e35732243fdb9e318fee7a99efaab4d3370c3bfdb31d1a9d3bd2a2729e74a501f3b1b4a
7
+ data.tar.gz: ce7fcafe49551d9a0cbb9d62496395524d21507053f48add1f9d06101ee123930e2d09d6c082b0c671f3edeb46fe4fd37832513b6c9198fb45e15ff760ecee05
@@ -0,0 +1,3 @@
1
+ [submodule "secp256k1"]
2
+ path = secp256k1
3
+ url = https://github.com/bitcoin-core/secp256k1.git
@@ -8,8 +8,8 @@ install:
8
8
  - echo "install nothing"
9
9
 
10
10
  before_install:
11
- - docker pull ciriethereum/ciri:latest
11
+ - docker pull ciriethereum/ciri-p2p-test:latest
12
12
 
13
13
  script:
14
- - docker run -v `pwd`:/app --rm ciriethereum/ciri:latest bash -c 'bundle install && bundle exec rspec'
14
+ - docker run -v `pwd`:/app --rm ciriethereum/ciri-p2p-test:latest bash -c 'bundle install && bundle exec rake'
15
15
 
@@ -0,0 +1,21 @@
1
+ FROM ruby:2.6.0-preview2 AS build
2
+
3
+ LABEL maintainer="Jiang Jinyang <jjyruby@gmail.com>"
4
+
5
+ # install bitcoin secp256k1
6
+ COPY . /app
7
+ WORKDIR /app
8
+ RUN rake install:secp256k1
9
+
10
+ # Runtime image
11
+ FROM ruby:2.6.0-preview2
12
+
13
+ # install runtime dependencies libraries
14
+ RUN apt-get update && apt-get install -y libsnappy-dev libgflags-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
15
+
16
+ # copy header files and shared libraries
17
+ COPY --from=build /usr/local/include /usr/local/include
18
+ COPY --from=build /usr/local/lib/ /usr/local/lib
19
+
20
+ WORKDIR /app
21
+
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ciri-p2p (0.1.0)
4
+ ciri-p2p (0.2.0)
5
5
  async (~> 1.10.3)
6
6
  async-io (~> 1.15.5)
7
7
  ciri-common (~> 0.1.0)
data/README.md CHANGED
@@ -3,10 +3,37 @@
3
3
 
4
4
  P2P network implementation for [Ciri Ethereum](https://github.com/ciri-ethereum/ciri).
5
5
 
6
- `ciri-p2p` is a DevP2P implementation, we also seek to implement LibP2P components upon ciri-p2p codebase in the future.
6
+ `ciri-p2p` is a [DevP2P](https://github.com/ethereum/devp2p) implementation, we also seek to implement [LibP2P](https://github.com/libp2p/libp2p) components upon ciri-p2p codebase in the future.
7
7
 
8
8
  ## Installation
9
9
 
10
+ ### Install dependencies
11
+
12
+ Ciri P2P depend on `secp256k1` to handle crypto signature and depend on `snappy` to compress data.
13
+
14
+ Build and install `secp256k1`
15
+
16
+ ``` bash
17
+ cd ciri
18
+ git submodule init && git submodule update
19
+ rake install:secp256k1
20
+ ```
21
+
22
+ On Mac you can install `snappy` with homebrew
23
+
24
+ ``` bash
25
+ brew install snappy
26
+ ```
27
+
28
+ For linux users, remember to check [Dockerfile](/docker) instructions for hint.
29
+
30
+ then run tests:
31
+ ``` bash
32
+ bundle exec rake spec
33
+ ```
34
+
35
+ ### Install as Gem
36
+
10
37
  Add this line to your application's Gemfile:
11
38
 
12
39
  ```ruby
@@ -23,7 +50,7 @@ Or install it yourself as:
23
50
 
24
51
  ## Usage
25
52
 
26
- Check spec directory.
53
+ Check [spec](https://github.com/ciri-ethereum/ciri-p2p/tree/master/spec) directory.
27
54
 
28
55
  ## Development
29
56
 
data/Rakefile CHANGED
@@ -1,6 +1,77 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
2
+ require 'fileutils'
3
+ require 'tmpdir'
3
4
 
4
- RSpec::Core::RakeTask.new(:spec)
5
+ begin
6
+ require "rspec/core/rake_task"
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ task :default => :spec
9
+ rescue LoadError
10
+ warn("rspec not installed, use `gem install rspec-core` to install")
11
+ end
12
+
13
+ namespace :install do
14
+ desc "Build and install secp256k1 shared library"
15
+ task :secp256k1 do
16
+ Dir.mktmpdir do |path|
17
+ source_dir = "secp256k1"
18
+ build_dir = "#{path}/#{source_dir}"
19
+ FileUtils.copy_entry source_dir, build_dir
20
+ Dir.chdir(build_dir)
21
+ run("./autogen.sh")
22
+ run("./configure --enable-module-recovery --enable-experimental --enable-module-ecdh")
23
+ run("make")
24
+ run("make install")
25
+ end
26
+ puts "Success installed secp256k1"
27
+ end
28
+
29
+ desc "Build and install all"
30
+ task all: [:secp256k1, :install]
31
+ end
32
+
33
+ namespace :docker do
34
+ base_image = 'ciriethereum/ciri-p2p-test'
35
+
36
+ desc 'pull docker image'
37
+ task :pull do
38
+ run("docker pull #{base_image}:latest")
39
+ end
40
+
41
+ desc 'build docker image, rerun this task after updated Gemfile or Dockerfile'
42
+ task :build do
43
+ system("git submodule init && git submodule update")
44
+ run("docker build . -f Dockerfile -t #{base_image}:latest")
45
+ end
46
+
47
+ desc 'push docker image'
48
+ task :push do
49
+ run("docker push #{base_image}:latest")
50
+ end
51
+
52
+ desc 'open Ciri P2P develop container shell'
53
+ task :shell do
54
+ container_name = 'ciri-p2p-develop'
55
+ if system("docker inspect #{container_name} > /dev/null")
56
+ system("docker start -i #{container_name}")
57
+ else
58
+ puts "start a new develop container: #{container_name}"
59
+ system("docker run -v `pwd`:/app -it --name #{container_name} #{base_image}:latest bash")
60
+ end
61
+ end
62
+
63
+ desc 'run spec in docker'
64
+ task :spec do |task, args|
65
+ run("docker run -v `pwd`:/app --rm #{base_image}:latest rake")
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def run(cmd)
72
+ puts "$ #{cmd}"
73
+ pid = spawn(cmd)
74
+ Process.wait(pid)
75
+ exit $?.exitstatus unless $?.success?
76
+ end
5
77
 
6
- task :default => :spec
@@ -5,7 +5,7 @@ require "ciri/p2p/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ciri-p2p"
8
- spec.version = Ciri::P2p::VERSION
8
+ spec.version = Ciri::P2P::VERSION
9
9
  spec.authors = ["jjy"]
10
10
  spec.email = ["jjyruby@gmail.com"]
11
11
 
@@ -54,7 +54,7 @@ module Ciri
54
54
  def dial_bootnodes
55
55
  @network_state.peer_store.find_bootnodes(@network_state.number_of_attemp_outgoing).each do |node|
56
56
  conn, handshake = @dialer.dial(node)
57
- @network_state.new_peer_connected(conn, handshake, way_for_connection: Peer::OUTGOING)
57
+ @network_state.new_peer_connected(conn, handshake, direction: Peer::OUTGOING)
58
58
  end
59
59
  end
60
60
 
@@ -63,7 +63,7 @@ module Ciri
63
63
  # avoid dial self or connected peers
64
64
  next if @network_state.peers.include?(node.raw_node_id) || node.raw_node_id == @network_state.local_node_id
65
65
  conn, handshake = @dialer.dial(node)
66
- @network_state.new_peer_connected(conn, handshake, way_for_connection: Peer::OUTGOING)
66
+ @network_state.new_peer_connected(conn, handshake, direction: Peer::OUTGOING)
67
67
  end
68
68
  end
69
69
  end
@@ -23,6 +23,7 @@
23
23
 
24
24
 
25
25
  require 'async'
26
+ require 'async/semaphore'
26
27
  require 'ciri/utils/logger'
27
28
  require_relative 'peer'
28
29
  require_relative 'errors'
@@ -40,6 +41,7 @@ module Ciri
40
41
 
41
42
  def initialize(protocols:, peer_store:, local_node_id:, max_outgoing: 10, max_incoming: 10, ping_interval_secs: 15)
42
43
  @peers = {}
44
+ @peers_lock = Async::Semaphore.new
43
45
  @peer_store = peer_store
44
46
  @protocols = protocols
45
47
  @local_node_id = local_node_id
@@ -60,35 +62,41 @@ module Ciri
60
62
  @max_outgoing - @peers.values.select(&:outgoing?).count
61
63
  end
62
64
 
63
- def new_peer_connected(connection, handshake, way_for_connection:, task: Async::Task.current)
64
- protocol_handshake_checks(handshake)
65
- peer = Peer.new(connection, handshake, @protocols, way_for_connection: way_for_connection)
66
- # disconnect already connected peers
67
- if @peers.include?(peer.raw_node_id)
68
- debug("[#{local_node_id.short_hex}] peer #{peer} is already connected")
69
- return
70
- end
71
- @peers[peer.raw_node_id] = peer
72
- debug "[#{local_node_id.short_hex}] connect to new peer #{peer}"
73
- @peer_store.update_peer_status(peer.raw_node_id, PeerStore::Status::CONNECTED)
74
- # run peer logic
75
- task.async do
76
- register_peer_protocols(peer)
77
- handling_peer(peer)
65
+ def new_peer_connected(connection, handshake, direction:, task: Async::Task.current)
66
+ @peers_lock.acquire do
67
+ peer = Peer.new(connection, handshake, @protocols, direction: direction)
68
+ # disconnect already connected peers
69
+ if @peers.include?(peer.raw_node_id)
70
+ debug("[#{local_node_id.short_hex}] peer #{peer.inspect} is already connected")
71
+ # disconnect duplicate connection
72
+ peer.disconnect
73
+ return
74
+ end
75
+ # check peers
76
+ protocol_handshake_checks(handshake)
77
+ @peers[peer.raw_node_id] = peer
78
+ debug "[#{local_node_id.short_hex}] connect to new peer #{peer.inspect}"
79
+ @peer_store.update_peer_status(peer.raw_node_id, PeerStore::Status::CONNECTED)
80
+ # run peer logic
81
+ task.async do
82
+ register_peer_protocols(peer)
83
+ handling_peer(peer)
84
+ end
78
85
  end
79
86
  end
80
87
 
81
- def remove_peer(peer)
82
- @peers.delete(peer.raw_node_id)
83
- deregister_peer_protocols(peer)
84
- end
85
-
86
88
  def disconnect_peer(peer, reason: nil)
87
- return unless @peers.include?(peer.raw_node_id)
88
- debug("[#{local_node_id.short_hex}] disconnect peer: #{peer}, reason: #{reason}")
89
- remove_peer(peer)
90
- peer.disconnect
91
- @peer_store.update_peer_status(peer.raw_node_id, PeerStore::Status::DISCONNECTED)
89
+ @peers_lock.acquire do
90
+ # only disconnect from peers if direction correct to avoiding delete peer by mistake
91
+ if (exist_peer = @peers[peer.raw_node_id]) && exist_peer.direction == peer.direction
92
+ debug("[#{local_node_id.short_hex}] disconnect peer: #{peer.inspect}, reason: #{reason}")
93
+ remove_peer(peer)
94
+ peer.disconnect
95
+ @peer_store.update_peer_status(peer.raw_node_id, PeerStore::Status::DISCONNECTED)
96
+ else
97
+ debug("[#{local_node_id.short_hex}] Ignoring: disconnect peer: #{peer.inspect}, reason: #{reason}")
98
+ end
99
+ end
92
100
  end
93
101
 
94
102
  def disconnect_all
@@ -100,6 +108,12 @@ module Ciri
100
108
 
101
109
  private
102
110
 
111
+ def remove_peer(peer)
112
+ @peers.delete(peer.raw_node_id)
113
+ deregister_peer_protocols(peer)
114
+ end
115
+
116
+
103
117
  def register_peer_protocols(peer, task: Async::Task.current)
104
118
  peer.protocol_ios.dup.each do |protocol_io|
105
119
  task.async do
@@ -107,7 +121,7 @@ module Ciri
107
121
  context = ProtocolContext.new(self, peer: peer, protocol: protocol_io.protocol, protocol_io: protocol_io)
108
122
  context.protocol.connected(context)
109
123
  rescue StandardError => e
110
- error("Protocol#connected error: {e}\nbacktrace: #{e.backtrace.join "\n"}")
124
+ error("Protocol#connected error: #{e}\nbacktrace: #{e.backtrace.join "\n"}")
111
125
  disconnect_peer(peer, reason: "Protocol#connected callback error: #{e}")
112
126
  end
113
127
  end
@@ -35,22 +35,22 @@ module Ciri
35
35
  OUTGOING = :outgoing
36
36
  INCOMING = :incoming
37
37
 
38
- attr_reader :connection
38
+ attr_reader :connection, :direction
39
39
 
40
- def initialize(connection, handshake, protocols, way_for_connection:)
40
+ def initialize(connection, handshake, protocols, direction:)
41
41
  @connection = connection
42
42
  @handshake = handshake
43
43
  @protocols = protocols
44
44
  @protocol_io_hash = make_protocol_io_hash(protocols, handshake.caps, connection)
45
- @way_for_connection = way_for_connection
45
+ @direction = direction
46
46
  end
47
47
 
48
48
  def outgoing?
49
- @way_for_connection == OUTGOING
49
+ @direction == OUTGOING
50
50
  end
51
51
 
52
52
  def incoming?
53
- @way_for_connection == INCOMING
53
+ @direction == INCOMING
54
54
  end
55
55
 
56
56
  def to_s
@@ -60,7 +60,7 @@ module Ciri
60
60
  end
61
61
 
62
62
  def inspect
63
- "<Peer:#{to_s}>"
63
+ "<Peer:#{to_s} direction: #{@direction}>"
64
64
  end
65
65
 
66
66
  def hash
@@ -148,7 +148,7 @@ module Ciri
148
148
  c = Connection.new(client)
149
149
  c.encryption_handshake!(private_key: @private_key)
150
150
  remote_handshake = c.protocol_handshake!(handshake)
151
- @network_state.new_peer_connected(c, remote_handshake, way_for_connection: Peer::INCOMING)
151
+ @network_state.new_peer_connected(c, remote_handshake, direction: Peer::INCOMING)
152
152
  end
153
153
  end
154
154
  end
@@ -1,5 +1,6 @@
1
1
  module Ciri
2
- module P2p
3
- VERSION = "0.1.0"
2
+ module P2P
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
6
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ciri-p2p
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - jjy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-13 00:00:00.000000000 Z
11
+ date: 2018-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ciri-utils
@@ -159,10 +159,11 @@ extensions: []
159
159
  extra_rdoc_files: []
160
160
  files:
161
161
  - ".gitignore"
162
+ - ".gitmodules"
162
163
  - ".rspec"
163
164
  - ".travis.yml"
164
- - ".vscode/launch.json"
165
165
  - CODE_OF_CONDUCT.md
166
+ - Dockerfile
166
167
  - Gemfile
167
168
  - Gemfile.lock
168
169
  - LICENSE.txt
@@ -1,90 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "name": "Debug Local File",
9
- "type": "Ruby",
10
- "request": "launch",
11
- "cwd": "${workspaceRoot}",
12
- "program": "${workspaceRoot}/main.rb"
13
- },
14
- {
15
- "name": "Listen for rdebug-ide",
16
- "type": "Ruby",
17
- "request": "attach",
18
- "cwd": "${workspaceRoot}",
19
- "remoteHost": "127.0.0.1",
20
- "remotePort": "1234",
21
- "remoteWorkspaceRoot": "${workspaceRoot}"
22
- },
23
- {
24
- "name": "Rails server",
25
- "type": "Ruby",
26
- "request": "launch",
27
- "cwd": "${workspaceRoot}",
28
- "program": "${workspaceRoot}/bin/rails",
29
- "args": [
30
- "server"
31
- ]
32
- },
33
- {
34
- "name": "RSpec - all",
35
- "type": "Ruby",
36
- "request": "launch",
37
- "cwd": "${workspaceRoot}",
38
- "program": "${workspaceRoot}/bin/rspec",
39
- "args": [
40
- "-I",
41
- "${workspaceRoot}"
42
- ]
43
- },
44
- {
45
- "name": "RSpec - quick",
46
- "type": "Ruby",
47
- "request": "launch",
48
- "cwd": "${workspaceRoot}",
49
- "program": "${workspaceRoot}/bin/rake",
50
- "args": [
51
- "test"
52
- ]
53
- },
54
- {
55
- "name": "RSpec - BlockChainSpec",
56
- "type": "Ruby",
57
- "request": "launch",
58
- "cwd": "${workspaceRoot}",
59
- "program": "${workspaceRoot}/bin/rspec",
60
- "args": [
61
- "-t",
62
- "~slow_tests",
63
- "spec/ciri/fixtures_tests/block_chain_spec.rb"
64
- ],
65
- "env": {
66
- "DEBUG": true,
67
- "RUBY_THREAD_VM_STACK_SIZE": 52428800
68
- }
69
- },
70
- {
71
- "name": "RSpec - active spec file only",
72
- "type": "Ruby",
73
- "request": "launch",
74
- "cwd": "${workspaceRoot}",
75
- "program": "${workspaceRoot}/bin/rspec",
76
- "args": [
77
- "-I",
78
- "${workspaceRoot}",
79
- "${file}"
80
- ]
81
- },
82
- {
83
- "name": "Cucumber",
84
- "type": "Ruby",
85
- "request": "launch",
86
- "cwd": "${workspaceRoot}",
87
- "program": "${workspaceRoot}/bin/cucumber"
88
- }
89
- ]
90
- }