ciri-p2p 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- }