reth 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +6 -0
- data/bin/reth +208 -0
- data/lib/reth.rb +44 -0
- data/lib/reth/account.rb +195 -0
- data/lib/reth/account_service.rb +361 -0
- data/lib/reth/app.rb +15 -0
- data/lib/reth/chain_service.rb +500 -0
- data/lib/reth/config.rb +88 -0
- data/lib/reth/db_service.rb +90 -0
- data/lib/reth/duplicates_filter.rb +29 -0
- data/lib/reth/eth_protocol.rb +209 -0
- data/lib/reth/genesisdata/genesis_frontier.json +26691 -0
- data/lib/reth/genesisdata/genesis_morden.json +27 -0
- data/lib/reth/genesisdata/genesis_olympic.json +48 -0
- data/lib/reth/jsonrpc.rb +13 -0
- data/lib/reth/jsonrpc/app.rb +79 -0
- data/lib/reth/jsonrpc/filter.rb +288 -0
- data/lib/reth/jsonrpc/handler.rb +424 -0
- data/lib/reth/jsonrpc/helper.rb +156 -0
- data/lib/reth/jsonrpc/server.rb +24 -0
- data/lib/reth/jsonrpc/service.rb +37 -0
- data/lib/reth/keystore.rb +150 -0
- data/lib/reth/leveldb_service.rb +79 -0
- data/lib/reth/profile.rb +66 -0
- data/lib/reth/sync_task.rb +273 -0
- data/lib/reth/synchronizer.rb +192 -0
- data/lib/reth/transient_block.rb +40 -0
- data/lib/reth/utils.rb +22 -0
- data/lib/reth/version.rb +3 -0
- metadata +201 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Reth
|
4
|
+
|
5
|
+
##
|
6
|
+
# Handles the synchronization of blocks.
|
7
|
+
#
|
8
|
+
# There's only one sync task active at a time. In order to deal with the
|
9
|
+
# worst case of initially syncing the wrong chain, a checkpoint blockhash
|
10
|
+
# can be specified and synced via force_sync.
|
11
|
+
#
|
12
|
+
# Received blocks are given to chainservice.add_block, which has a fixed
|
13
|
+
# size queue, the synchronization blocks if the queue is full.
|
14
|
+
#
|
15
|
+
# on_status:
|
16
|
+
# if peer.head.chain_difficulty > chain.head.chain_difficulty
|
17
|
+
# fetch peer.head and handle as newblock
|
18
|
+
#
|
19
|
+
# on_newblock:
|
20
|
+
# if block.parent
|
21
|
+
# add
|
22
|
+
# else
|
23
|
+
# sync
|
24
|
+
#
|
25
|
+
# on_blocks/on_blockhashes:
|
26
|
+
# if synctask
|
27
|
+
# handle to requester
|
28
|
+
# elsif unkonwn and has parent
|
29
|
+
# add to chain
|
30
|
+
# else
|
31
|
+
# drop
|
32
|
+
#
|
33
|
+
class Synchronizer
|
34
|
+
|
35
|
+
MAX_NEWBLOCK_AGE = 5 # maximum age (in blocks) of blocks received as newblock
|
36
|
+
|
37
|
+
attr :chain, :chainservice, :synctask
|
38
|
+
|
39
|
+
##
|
40
|
+
# @param force_sync [Array, NilClass] If passed in array, it must be in
|
41
|
+
# the form of tuple: (blockhash, chain_difficulty). Helper for long
|
42
|
+
# initial syncs to get on the right chain used with first
|
43
|
+
# status_received.
|
44
|
+
#
|
45
|
+
def initialize(chainservice, force_sync=nil)
|
46
|
+
@chainservice = chainservice
|
47
|
+
@force_sync = force_sync
|
48
|
+
@chain = chainservice.chain
|
49
|
+
@protocols = {} # proto => chain_difficulty
|
50
|
+
@synctask = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def syncing?
|
54
|
+
!!@synctask
|
55
|
+
end
|
56
|
+
|
57
|
+
def synctask_exited(success=false)
|
58
|
+
@force_sync = nil if success
|
59
|
+
@synctask = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def protocols
|
63
|
+
@protocols = @protocols
|
64
|
+
.map {|proto, diff| [proto, diff] }
|
65
|
+
.select {|tuple| !tuple[0].stopped? }
|
66
|
+
.to_h
|
67
|
+
|
68
|
+
@protocols.keys.sort_by {|proto| -@protocols[proto] }
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Called if there's a newblock announced on the network.
|
73
|
+
#
|
74
|
+
def receive_newblock(proto, t_block, chain_difficulty)
|
75
|
+
logger.debug 'newblock', proto: proto, block: t_block, chain_difficulty: chain_difficulty, client: proto.peer.remote_client_version
|
76
|
+
|
77
|
+
if @chain.include?(t_block.header.full_hash)
|
78
|
+
raise AssertError, 'chain difficulty mismatch' unless chain_difficulty == @chain.get(t_block.header.full_hash).chain_difficulty
|
79
|
+
end
|
80
|
+
|
81
|
+
@protocols[proto] = chain_difficulty
|
82
|
+
|
83
|
+
if @chainservice.knows_block(t_block.header.full_hash)
|
84
|
+
logger.debug 'known block'
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
expected_difficulty = @chain.head.chain_difficulty + t_block.header.difficulty
|
89
|
+
if chain_difficulty >= @chain.head.chain_difficulty
|
90
|
+
# broadcast duplicates filtering is done in chainservice
|
91
|
+
logger.debug 'sufficient difficulty, broadcasting', client: proto.peer.remote_client_version
|
92
|
+
@chainservice.broadcast_newblock t_block, chain_difficulty, proto
|
93
|
+
else
|
94
|
+
age = @chain.head.number - t_block.header.number
|
95
|
+
logger.debug "low difficulty", client: proto.peer.remote_client_version, chain_difficulty: chain_difficulty, expected_difficulty: expected_difficulty, block_age: age
|
96
|
+
|
97
|
+
if age > MAX_NEWBLOCK_AGE
|
98
|
+
logger.debug 'newblock is too old, not adding', block_age: age, max_age: MAX_NEWBLOCK_AGE
|
99
|
+
return
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
if @chainservice.knows_block(t_block.header.prevhash)
|
104
|
+
logger.debug 'adding block'
|
105
|
+
@chainservice.add_block t_block, proto
|
106
|
+
else
|
107
|
+
logger.debug 'missing parent'
|
108
|
+
if @synctask
|
109
|
+
logger.debug 'existing task, discarding'
|
110
|
+
else
|
111
|
+
@synctask = SyncTask.new self, proto, t_block.header.full_hash, chain_difficulty
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Called if a new peer is connected.
|
118
|
+
#
|
119
|
+
def receive_status(proto, blockhash, chain_difficulty)
|
120
|
+
logger.debug 'status received', proto: proto, chain_difficulty: chain_difficulty
|
121
|
+
|
122
|
+
@protocols[proto] = chain_difficulty
|
123
|
+
|
124
|
+
if @chainservice.knows_block(blockhash) || @synctask
|
125
|
+
logger.debug 'existing task or known hash, discarding'
|
126
|
+
return
|
127
|
+
end
|
128
|
+
|
129
|
+
if @force_sync
|
130
|
+
blockhash, difficulty = force_sync
|
131
|
+
logger.debug 'starting forced synctask', blockhash: Utils.encode_hex(blockhash)
|
132
|
+
@synctask = SyncTask.new self, proto, blockhash, difficulty
|
133
|
+
elsif chain_difficulty > @chain.head.chain_difficulty
|
134
|
+
logger.debug 'sufficient difficulty'
|
135
|
+
@synctask = SyncTask.new self, proto, blockhash, chain_difficulty
|
136
|
+
end
|
137
|
+
rescue
|
138
|
+
logger.debug $!
|
139
|
+
logger.debug $!.backtrace[0,10].join("\n")
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# No way to check if this really an interesting block at this point.
|
144
|
+
# Might lead to an amplification attack, need to track this proto and
|
145
|
+
# judge usefulness.
|
146
|
+
#
|
147
|
+
def receive_newblockhashes(proto, newblockhashes)
|
148
|
+
logger.debug 'received newblockhashes', num: newblockhashes.size, proto: proto
|
149
|
+
|
150
|
+
newblockhashes = newblockhashes.select {|h| !@chainservice.knows_block(h) }
|
151
|
+
|
152
|
+
known = @protocols.include?(proto)
|
153
|
+
if !known || newblockhashes.empty? || @synctask
|
154
|
+
logger.debug 'discarding', known: known, synctask: syncing?, num: newblockhashes.size
|
155
|
+
return
|
156
|
+
end
|
157
|
+
|
158
|
+
if newblockhashes.size != 1
|
159
|
+
logger.warn 'supporting only one newblockhash', num: newblockhashes.size
|
160
|
+
end
|
161
|
+
blockhash = newblockhashes[0]
|
162
|
+
|
163
|
+
logger.debug 'starting synctask for newblockhashes', blockhash: Utils.encode_hex(blockhash)
|
164
|
+
@synctask = SyncTask.new self, proto, blockhash, 0, true
|
165
|
+
end
|
166
|
+
|
167
|
+
def receive_blocks(proto, t_blocks)
|
168
|
+
logger.debug 'blocks received', proto: proto, num: t_blocks.size
|
169
|
+
if @synctask
|
170
|
+
@synctask.receive_blocks proto, t_blocks
|
171
|
+
else
|
172
|
+
logger.warn 'no synctask, not expecting blocks'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def receive_blockhashes(proto, blockhashes)
|
177
|
+
logger.debug 'blockhashes received', proto: proto, num: blockhashes.size
|
178
|
+
if @synctask
|
179
|
+
@synctask.receive_blockhashes proto, blockhashes
|
180
|
+
else
|
181
|
+
logger.warn 'no synctask, not expecting blockhashes'
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def logger
|
188
|
+
@logger ||= Logger.new('eth.sync')
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Reth
|
4
|
+
|
5
|
+
class TransientBlock
|
6
|
+
include RLP::Sedes::Serializable
|
7
|
+
|
8
|
+
set_serializable_fields(
|
9
|
+
header: BlockHeader,
|
10
|
+
transaction_list: RLP::Sedes::CountableList.new(Transaction),
|
11
|
+
uncles: RLP::Sedes::CountableList.new(BlockHeader)
|
12
|
+
)
|
13
|
+
|
14
|
+
attr :newblock_timestamp
|
15
|
+
|
16
|
+
def initialize(block_data, newblock_timestamp=0)
|
17
|
+
@newblock_timestamp = newblock_timestamp
|
18
|
+
|
19
|
+
header = BlockHeader.deserialize block_data[0]
|
20
|
+
transaction_list = RLP::Sedes::CountableList.new(Transaction).deserialize block_data[1]
|
21
|
+
uncles = RLP::Sedes::CountableList.new(BlockHeader).deserialize block_data[2]
|
22
|
+
super(header, transaction_list, uncles)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_block(env, parent=nil)
|
26
|
+
Block.new header: header, transaction_list: transaction_list, uncles: uncles, env: env, parent: parent
|
27
|
+
end
|
28
|
+
|
29
|
+
def full_hash_hex
|
30
|
+
header.full_hash_hex
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"<TransientBlock(##{header.number} #{header.full_hash_hex[0,8]})"
|
35
|
+
end
|
36
|
+
alias inspect to_s
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/reth/utils.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Reth
|
6
|
+
|
7
|
+
module Utils
|
8
|
+
|
9
|
+
include ::Ethereum::Utils
|
10
|
+
extend self
|
11
|
+
|
12
|
+
def mk_random_privkey
|
13
|
+
SecureRandom.random_bytes(32)
|
14
|
+
end
|
15
|
+
|
16
|
+
def mk_privkey(seed)
|
17
|
+
keccak256 seed
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/reth/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Xie
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-ethereum
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.9.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: devp2p
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: slop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sinatra
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.4'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sinatra-contrib
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.4'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.4'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.5'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 5.8.3
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 5.8.3
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.8.7.6
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.8.7.6
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: serpent
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.3'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.3'
|
139
|
+
description: A ethereum full node written in ruby.
|
140
|
+
email:
|
141
|
+
- jan.h.xie@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- LICENSE
|
147
|
+
- README.md
|
148
|
+
- bin/reth
|
149
|
+
- lib/reth.rb
|
150
|
+
- lib/reth/account.rb
|
151
|
+
- lib/reth/account_service.rb
|
152
|
+
- lib/reth/app.rb
|
153
|
+
- lib/reth/chain_service.rb
|
154
|
+
- lib/reth/config.rb
|
155
|
+
- lib/reth/db_service.rb
|
156
|
+
- lib/reth/duplicates_filter.rb
|
157
|
+
- lib/reth/eth_protocol.rb
|
158
|
+
- lib/reth/genesisdata/genesis_frontier.json
|
159
|
+
- lib/reth/genesisdata/genesis_morden.json
|
160
|
+
- lib/reth/genesisdata/genesis_olympic.json
|
161
|
+
- lib/reth/jsonrpc.rb
|
162
|
+
- lib/reth/jsonrpc/app.rb
|
163
|
+
- lib/reth/jsonrpc/filter.rb
|
164
|
+
- lib/reth/jsonrpc/handler.rb
|
165
|
+
- lib/reth/jsonrpc/helper.rb
|
166
|
+
- lib/reth/jsonrpc/server.rb
|
167
|
+
- lib/reth/jsonrpc/service.rb
|
168
|
+
- lib/reth/keystore.rb
|
169
|
+
- lib/reth/leveldb_service.rb
|
170
|
+
- lib/reth/profile.rb
|
171
|
+
- lib/reth/sync_task.rb
|
172
|
+
- lib/reth/synchronizer.rb
|
173
|
+
- lib/reth/transient_block.rb
|
174
|
+
- lib/reth/utils.rb
|
175
|
+
- lib/reth/version.rb
|
176
|
+
homepage: https://github.com/janx/reth
|
177
|
+
licenses:
|
178
|
+
- MIT
|
179
|
+
metadata: {}
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
require_paths:
|
183
|
+
- lib
|
184
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - ">="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
requirements: []
|
195
|
+
rubyforge_project:
|
196
|
+
rubygems_version: 2.4.5.1
|
197
|
+
signing_key:
|
198
|
+
specification_version: 4
|
199
|
+
summary: Ethereum full node.
|
200
|
+
test_files: []
|
201
|
+
has_rdoc:
|