ciri 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +14 -0
  3. data/.rspec +2 -1
  4. data/.travis.yml +11 -4
  5. data/Gemfile.lock +3 -0
  6. data/README.md +44 -34
  7. data/Rakefile +47 -4
  8. data/ciri.gemspec +13 -12
  9. data/docker/Base +34 -0
  10. data/lib/ciri/actor.rb +223 -0
  11. data/lib/ciri/chain.rb +293 -0
  12. data/lib/ciri/chain/block.rb +47 -0
  13. data/lib/ciri/chain/header.rb +62 -0
  14. data/lib/ciri/chain/transaction.rb +145 -0
  15. data/lib/ciri/crypto.rb +58 -5
  16. data/lib/ciri/db/backend/memory.rb +68 -0
  17. data/lib/ciri/db/backend/rocks.rb +104 -0
  18. data/lib/ciri/db/backend/rocks_db.rb +278 -0
  19. data/lib/ciri/devp2p/peer.rb +10 -2
  20. data/lib/ciri/devp2p/protocol.rb +11 -3
  21. data/lib/ciri/devp2p/protocol_io.rb +6 -3
  22. data/lib/ciri/devp2p/rlpx.rb +1 -0
  23. data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +1 -1
  24. data/lib/ciri/devp2p/rlpx/frame_io.rb +1 -1
  25. data/lib/ciri/devp2p/rlpx/message.rb +4 -4
  26. data/lib/ciri/devp2p/server.rb +14 -13
  27. data/lib/ciri/eth.rb +33 -0
  28. data/lib/ciri/eth/peer.rb +64 -0
  29. data/lib/ciri/eth/protocol_manage.rb +122 -0
  30. data/lib/ciri/eth/protocol_messages.rb +158 -0
  31. data/lib/ciri/eth/synchronizer.rb +188 -0
  32. data/lib/ciri/ethash.rb +123 -0
  33. data/lib/ciri/evm.rb +140 -0
  34. data/lib/ciri/evm/account.rb +50 -0
  35. data/lib/ciri/evm/block_info.rb +31 -0
  36. data/lib/ciri/evm/forks/frontier.rb +183 -0
  37. data/lib/ciri/evm/instruction.rb +92 -0
  38. data/lib/ciri/evm/machine_state.rb +81 -0
  39. data/lib/ciri/evm/op.rb +536 -0
  40. data/lib/ciri/evm/serialize.rb +60 -0
  41. data/lib/ciri/evm/sub_state.rb +64 -0
  42. data/lib/ciri/evm/vm.rb +379 -0
  43. data/lib/ciri/forks.rb +38 -0
  44. data/lib/ciri/forks/frontier.rb +43 -0
  45. data/lib/ciri/key.rb +7 -1
  46. data/lib/ciri/pow.rb +95 -0
  47. data/lib/ciri/rlp.rb +3 -53
  48. data/lib/ciri/rlp/decode.rb +100 -40
  49. data/lib/ciri/rlp/encode.rb +95 -34
  50. data/lib/ciri/rlp/serializable.rb +61 -91
  51. data/lib/ciri/types/address.rb +70 -0
  52. data/lib/ciri/types/errors.rb +36 -0
  53. data/lib/ciri/utils.rb +45 -13
  54. data/lib/ciri/utils/lib_c.rb +46 -0
  55. data/lib/ciri/utils/logger.rb +99 -0
  56. data/lib/ciri/utils/number.rb +67 -0
  57. data/lib/ciri/version.rb +1 -1
  58. metadata +67 -7
  59. data/lib/ciri/devp2p/actor.rb +0 -224
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fb4f5d7ae9d525c598590327ea9652617ca2d48eff3edd40c36307d9b140fbf
4
- data.tar.gz: d45c159bc70ba765cae8d6b4150e3088ad8e43f55ec7e3f4cf691152604aa8ce
3
+ metadata.gz: abe8d78482df9ed72840456def4146338c14d14fe797d8a97ff8bbe1a93f1243
4
+ data.tar.gz: 65f245e4ec4aa14c2747745976a350ceee764c08f8e010e6586e6c8ba5a57227
5
5
  SHA512:
6
- metadata.gz: 35f02c14a3401ab6bbcfae9617ce1b4872a71e9117b05d5ac99e5795c2027d7a8c7e448cce617b25a120cc3da7ecda24eea6fe7ea91689d88457840c0b2fc41b
7
- data.tar.gz: d1867a3cc573020f8e5b1466d701029646598c748f1fdc405f34123120b77035ff369c9a6b92fa29e08072d1f5de9bc738f756c8071e24929afbc6f5868b2af1
6
+ metadata.gz: 478a4f654e958caa242c46881120d7737a7b74a72f142a05e29ea83fa32daef22d0a63832f9fc4ef649c9a8860e3be5226a376304d52de78ac1ec1e9ad1005b2
7
+ data.tar.gz: 556717e91e6dd17e22aeadd6c9f322ffd7d95540bbfcb9bfa775acdafa63a31e149bba971dd4e03ea935eba24d5f3a4f77bde2ba52c0bbe2e2f32b872c86afad
@@ -0,0 +1,14 @@
1
+ [submodule "secp256k1"]
2
+ path = secp256k1
3
+ url = https://github.com/bitcoin-core/secp256k1.git
4
+ [submodule "rocksdb"]
5
+ path = rocksdb
6
+ url = https://github.com/facebook/rocksdb.git
7
+ [submodule "ethash"]
8
+ path = ethash
9
+ url = https://github.com/ciri-ethereum/ethash.git
10
+ branch = shared_library
11
+ [submodule "fixtures"]
12
+ path = fixtures
13
+ url = https://github.com/ethereum/tests.git
14
+ branch = develop
data/.rspec CHANGED
@@ -1,3 +1,4 @@
1
- --format documentation
1
+ --format progress
2
2
  --color
3
3
  --require spec_helper
4
+ --profile
@@ -1,5 +1,12 @@
1
- sudo: false
1
+ sudo: required
2
2
  language: ruby
3
- rvm:
4
- - 2.5.0
5
- before_install: gem install bundler -v 1.16.1
3
+
4
+ services:
5
+ - docker
6
+
7
+ before_install:
8
+ - docker pull ciriethereum/base:latest
9
+ - gem install rake
10
+
11
+ script:
12
+ - rake docker:test
@@ -5,6 +5,8 @@ PATH
5
5
  bitcoin-secp256k1 (~> 0.4.0)
6
6
  concurrent-ruby (~> 1.0.5)
7
7
  digest-sha3 (~> 1.1.0)
8
+ ffi (~> 1.9.23)
9
+ lru_redux (~> 1.1.0)
8
10
  snappy (~> 0.0.17)
9
11
 
10
12
  GEM
@@ -16,6 +18,7 @@ GEM
16
18
  diff-lcs (1.3)
17
19
  digest-sha3 (1.1.0)
18
20
  ffi (1.9.23)
21
+ lru_redux (1.1.0)
19
22
  rake (10.3.2)
20
23
  rspec (3.7.0)
21
24
  rspec-core (~> 3.7.0)
data/README.md CHANGED
@@ -1,49 +1,59 @@
1
1
  Ciri
2
2
  ===============
3
+ [![Build Status](https://travis-ci.org/ciri-ethereum/ciri.svg?branch=master)](https://travis-ci.org/ciri-ethereum/ciri)
4
+ [![Gitter](https://badges.gitter.im/join.svg)](https://gitter.im/ciri-ethereum/Lobby)
3
5
 
4
6
  Ciri project intent to implement a full feature set ethereum client.
5
7
 
6
- ### Check List
7
-
8
- * [ ] RLPX
9
- * [x] HandShake
10
- * [ ] Server
11
- * [ ] Node Discovery
12
- * [x] RLP
13
- * [ ] Eth Protocol
14
- * [x] HandShake
15
- * [ ] Ethereum Sub-protocol
16
- * [ ] Block Chain
17
- * [ ] Chain Syncing
18
- * [ ] EVM
19
- * [ ] Mining
20
- * [ ] Consensus Algorithm
21
- * [ ] POW
22
- * [ ] POS
23
- * [ ] Web3 RPC
24
- * [ ] CLI
25
-
26
- ### Install
8
+ It aims to be a feature complete, long maintained and stable ethereum client.
9
+ As you see it'is still under development.
27
10
 
28
- ``` bash
29
- gem install ciri
30
- ```
11
+ Talk to me on [gitter](https://gitter.im/ciri-ethereum/Lobby) if you interesting in this project or want to contributing.
12
+
13
+ See [projects](https://github.com/ciri-ethereum/ciri/projects) and [milestones](https://github.com/ciri-ethereum/ciri/milestones) for current development status.
31
14
 
32
- As library
15
+ Installation
16
+ ---------------
33
17
 
34
- ``` ruby
35
- require 'ciri'
36
- puts Ciri::Version
37
- ```
18
+ See [develop](#develop) section
38
19
 
39
- ### Command line
20
+ Usage
21
+ ---------------
40
22
 
41
23
  `ciri -h`
42
24
 
43
- ### Documentation
25
+ Develop
26
+ ---------------
27
+
28
+ Ciri depends on [rocksdb](https://github.com/facebook/rocksdb), [secp256k1](https://github.com/bitcoin-core/secp256k1), [ethash](https://github.com/ethereum/ethash) and [snappy](https://github.com/google/snappy).
29
+
30
+ It's recommended to use docker to handle dependencies:
31
+ ``` bash
32
+ # make sure we have installed docker, ruby and rake
33
+ docker -v
34
+ gem install rake
35
+
36
+ # pull Ciri base image
37
+ rake docker:pull_base
38
+ # run tests
39
+ rake docker:test
40
+ # open a shell for develop
41
+ rake docker:shell
42
+
43
+ # cool, type 'rake -T' see other supported tasks
44
+ ```
45
+
46
+ Otherwise you need install these libraries manually (remember check [docker](/docker) directory for hint).
47
+
48
+ then run:
49
+ `bundle install && bundle exec rake`
50
+
51
+ Documentation
52
+ ---------------
44
53
 
45
- [YARD documentation](https://www.rubydoc.info/github/ruby-ethereum/ciri/master)
54
+ [YARD documentation](https://www.rubydoc.info/github/ciri-ethereum/ciri/master)
46
55
 
47
- ### Author
56
+ Authors
57
+ ---------------
48
58
 
49
- [Jiang Jinyang](https://justjjy.com)
59
+ * [Jiang Jinyang](https://justjjy.com) (jjyruby@gmail.com)
data/Rakefile CHANGED
@@ -1,6 +1,49 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ begin
2
+ require "bundler/gem_tasks"
3
+ rescue LoadError
4
+ puts "bundler not installed, use 'gem install bundler' to install"
5
+ end
3
6
 
4
- RSpec::Core::RakeTask.new(:spec)
7
+ begin
8
+ require "rspec/core/rake_task"
9
+ RSpec::Core::RakeTask.new(:spec)
10
+ task :default => :spec
11
+ rescue LoadError
12
+ nil
13
+ end
5
14
 
6
- task :default => :spec
15
+ namespace :docker do
16
+ base_image = 'ciriethereum/base'
17
+
18
+ desc 'pull base docker image'
19
+ task :pull_base do
20
+ system("docker pull #{base_image}:latest")
21
+ end
22
+
23
+ desc 'build base docker image, rerun this task after updated Gemfile or Dockerfile'
24
+ task :build_base do
25
+ system("git submodule init && git submodule update")
26
+ system("docker build . -f docker/Base -t #{base_image}:latest")
27
+ end
28
+
29
+ desc 'open Ciri develop container shell'
30
+ task :shell do
31
+ container_name = 'ciri-develop'
32
+ if system("docker inspect #{container_name} > /dev/null")
33
+ system("docker start -i #{container_name}")
34
+ else
35
+ puts "start a new develop container: #{container_name}"
36
+ system("docker run -v `pwd`:/app -it --name #{container_name} #{base_image}:latest bash")
37
+ end
38
+ end
39
+
40
+ desc 'run tests in docker'
41
+ task :test do
42
+ system("docker run -v `pwd`:/app --rm #{base_image}:latest rspec -t ~slow_tests")
43
+ end
44
+
45
+ desc 'run all tests(include slow tests) in docker'
46
+ task :"test:all" do
47
+ system("docker run -v `pwd`:/app --rm #{base_image}:latest rspec")
48
+ end
49
+ end
@@ -1,26 +1,27 @@
1
-
2
1
  lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "ciri/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "ciri"
8
- spec.version = Ciri::VERSION
9
- spec.authors = ["Jiang Jinyang"]
10
- spec.email = ["jjyruby@gmail.com"]
6
+ spec.name = "ciri"
7
+ spec.version = Ciri::VERSION
8
+ spec.authors = ["Jiang Jinyang"]
9
+ spec.email = ["jjyruby@gmail.com"]
11
10
 
12
- spec.summary = %q{Ruby implementation of the ethereum}
13
- spec.description = %q{Ciri project intent to implement full feature set of ethereum in pure ruby, to provide both usable cli and well documented ruby library.}
14
- spec.homepage = "https://github.com/ruby-ethereum/ethereum"
15
- spec.license = "MIT"
11
+ spec.summary = %q{Ciri ethereum client.}
12
+ spec.description = %q{Ciri project intent to implement a full feature set ethereum client.}
13
+ spec.homepage = "https://github.com/ciri-ethereum/ciri"
14
+ spec.license = "MIT"
16
15
 
17
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
17
  f.match(%r{^(test|spec|features)/})
19
18
  end
20
- spec.bindir = "exe"
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f)}
22
21
  spec.require_paths = ["lib"]
23
22
 
23
+ spec.add_dependency 'ffi', '~> 1.9.23'
24
+ spec.add_dependency 'lru_redux', '~> 1.1.0'
24
25
  spec.add_dependency 'digest-sha3', '~> 1.1.0'
25
26
  spec.add_dependency 'bitcoin-secp256k1', '~> 0.4.0'
26
27
  spec.add_dependency 'concurrent-ruby', '~> 1.0.5'
@@ -0,0 +1,34 @@
1
+ FROM ruby:2.5.1
2
+ MAINTAINER Jiang Jinyang<jjyruby@gmail.com>
3
+
4
+ RUN apt-get update -y
5
+ RUN apt-get install -y cmake
6
+
7
+ # install bitcoin secp256k1
8
+ COPY ./secp256k1 /build/secp256k1
9
+ WORKDIR /build/secp256k1
10
+ RUN ./autogen.sh
11
+ RUN ./configure --enable-module-recovery --enable-experimental --enable-module-ecdh
12
+ RUN make && make install
13
+
14
+ # install ethash
15
+ COPY ./ethash /build/ethash
16
+ WORKDIR /build/ethash/src/libethash
17
+ RUN cmake CMakeLists.txt
18
+ RUN make install
19
+
20
+ # install RocksDB
21
+ RUN apt-get install -y libgflags-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
22
+ COPY ./rocksdb /build/rocksdb
23
+ WORKDIR /build/rocksdb
24
+ RUN make shared_lib
25
+ RUN make install-shared
26
+
27
+ # install snappy
28
+ RUN apt-get install -y libsnappy-dev
29
+
30
+ WORKDIR /app
31
+ COPY . /app
32
+
33
+ # bundle
34
+ RUN bundle install
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.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 'logger'
25
+
26
+ module Ciri
27
+
28
+ # simple actor model implementation
29
+ # Example:
30
+ #
31
+ # class Hello
32
+ # include Actor
33
+ #
34
+ # def say_hello
35
+ # puts 'hello world'
36
+ # 'hello world'
37
+ # end
38
+ # end
39
+ #
40
+ # actor = Hello.new()
41
+ # # start actor loop
42
+ # actor.start
43
+ # # push message to actor inbox
44
+ # actor << :say_hello
45
+ # # push message and wait until get response
46
+ # actor.call(:say_hello).value
47
+ #
48
+ # # raise error
49
+ # actor.call(:hello).value # NoMethodError
50
+ #
51
+ # # stop actor
52
+ # actor.send_stop
53
+ # actor.wait
54
+ #
55
+ module Actor
56
+
57
+ LOGGER = Logger.new(STDERR, datetime_format: '%Y-%m-%d %H:%M:%S', level: Logger::INFO)
58
+
59
+ # future, use this to wait actor msg respond
60
+ class Future
61
+ def initialize
62
+ @value = nil
63
+ @done = false
64
+ @queue = Queue.new
65
+ end
66
+
67
+ def value=(val)
68
+ if @done
69
+ raise RuntimeError.new('future value duplicated set')
70
+ end
71
+ @done = true
72
+ @queue << :done if @queue
73
+ @value = val
74
+ end
75
+
76
+ def value
77
+ loop do
78
+ if @done
79
+ return @value
80
+ elsif @error
81
+ raise @error
82
+ else
83
+ @queue.pop
84
+ end
85
+ end
86
+ end
87
+
88
+ def raise_error(error)
89
+ error.set_backtrace(caller) if error.backtrace.nil?
90
+ @error = error
91
+ @queue << :error if @queue
92
+ end
93
+ end
94
+
95
+ class Error < StandardError
96
+ end
97
+
98
+ # stop actor
99
+ class StopError < Error
100
+ end
101
+
102
+ class StateError < Error
103
+ end
104
+
105
+ class << self
106
+ attr_accessor :default_executor
107
+ end
108
+
109
+ attr_accessor :executor
110
+
111
+ def initialize(executor: Actor.default_executor)
112
+ @inbox = Queue.new
113
+ @executor = executor
114
+ @future = Future.new
115
+ @running = false
116
+ end
117
+
118
+ # async call
119
+ def enqueue(method, *args)
120
+ self << [method, *args]
121
+ end
122
+
123
+ def <<(args)
124
+ @inbox << args
125
+ end
126
+
127
+ # sync call, push msg to inbox, and return future
128
+ #
129
+ # Example:
130
+ # future = actor.call(:result) # future
131
+ # future.value # blocking and wait for result
132
+ #
133
+ def call(method, *args)
134
+ future = Future.new
135
+ self << [future, method, *args]
136
+ future
137
+ end
138
+
139
+ # start actor
140
+ def start
141
+ raise Error.new("must set executor before start") unless executor
142
+
143
+ @running = true
144
+ executor.post do
145
+ start_loop
146
+ end
147
+ end
148
+
149
+ # send stop to actor
150
+ #
151
+ # Example:
152
+ # actor.send_stop
153
+ # # wait for actor actually stopped
154
+ # actor.wait
155
+ #
156
+ def send_stop
157
+ self << [:raise_error, StopError.new]
158
+ end
159
+
160
+ # wait until an error occurs
161
+ def wait
162
+ raise StateError.new('actor not running!') unless @running
163
+ @future.value
164
+ end
165
+
166
+ # start loop
167
+ def start_loop
168
+ loop_callback do |wait_message: true|
169
+ # check inbox
170
+ next Thread.pass if @inbox.empty? && !wait_message
171
+ msg = @inbox.pop
172
+
173
+ # extract sync or async call
174
+ future = nil
175
+ method, *args = msg
176
+ if method.is_a?(Future)
177
+ future = method
178
+ method, *args = args
179
+ end
180
+ begin
181
+ val = send(method, *args)
182
+ rescue StandardError => e
183
+ future.raise_error(e) if future
184
+ raise
185
+ end
186
+ # if future not nil, set value
187
+ future.value = val if future
188
+ end until @inbox.closed?
189
+
190
+ rescue StopError
191
+ # actor stop
192
+ @future.value = nil
193
+ rescue StandardError => e
194
+ @future.raise_error e
195
+ LOGGER.error("Actor #{self}") {"#{e}\n#{e.backtrace.join("\n")}"}
196
+ ensure
197
+ @running = false
198
+ @inbox.close
199
+ end
200
+
201
+ # allow inject callback into actor loop
202
+ # Example:
203
+ #
204
+ # class A
205
+ # include Actor
206
+ #
207
+ # def loop_callback
208
+ # # before handle msg
209
+ # yield
210
+ # # after handle msg
211
+ # end
212
+ # end
213
+ #
214
+ def loop_callback
215
+ yield
216
+ end
217
+
218
+ def raise_error(e)
219
+ raise e
220
+ end
221
+ end
222
+
223
+ end