reth 0.1.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.
@@ -0,0 +1,27 @@
1
+ {
2
+ "nonce": "0x00006d6f7264656e",
3
+ "difficulty": "0x20000",
4
+ "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
5
+ "coinbase": "0x0000000000000000000000000000000000000000",
6
+ "timestamp": "0x00",
7
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
8
+ "extraData": "0x",
9
+ "gasLimit": "0x2FEFD8",
10
+ "alloc": {
11
+ "0000000000000000000000000000000000000001": {
12
+ "balance": "1"
13
+ },
14
+ "0000000000000000000000000000000000000002": {
15
+ "balance": "1"
16
+ },
17
+ "0000000000000000000000000000000000000003": {
18
+ "balance": "1"
19
+ },
20
+ "0000000000000000000000000000000000000004": {
21
+ "balance": "1"
22
+ },
23
+ "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": {
24
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "nonce": "0x0000000000000042",
3
+ "difficulty": "0x20000",
4
+ "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
5
+ "coinbase": "0x0000000000000000000000000000000000000000",
6
+ "timestamp": "0x00",
7
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
8
+ "extraData": "",
9
+ "gasLimit": "0x2fefd8",
10
+ "alloc": {
11
+ "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {
12
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
13
+ },
14
+ "e6716f9544a56c530d868e4bfbacb172315bdead": {
15
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
16
+ },
17
+ "b9c015918bdaba24b4ff057a92a3873d6eb201be": {
18
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
19
+ },
20
+ "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {
21
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
22
+ },
23
+ "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {
24
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
25
+ },
26
+ "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {
27
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
28
+ },
29
+ "6c386a4b26f73c802f34673f7248bb118f97424a": {
30
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
31
+ },
32
+ "e4157b34ea9615cfbde6b4fda419828124b70c78": {
33
+ "balance": "1606938044258990275541962092341162602522202993782792835301376"
34
+ },
35
+ "0000000000000000000000000000000000000001": {
36
+ "balance": "1"
37
+ },
38
+ "0000000000000000000000000000000000000002": {
39
+ "balance": "1"
40
+ },
41
+ "0000000000000000000000000000000000000003": {
42
+ "balance": "1"
43
+ },
44
+ "0000000000000000000000000000000000000004": {
45
+ "balance": "1"
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+ require 'rack'
3
+ require 'sinatra/base'
4
+ require 'sinatra/json'
5
+
6
+ require 'ethereum'
7
+
8
+ require 'reth/jsonrpc/helper'
9
+ require 'reth/jsonrpc/filter'
10
+ require 'reth/jsonrpc/handler'
11
+ require 'reth/jsonrpc/server'
12
+ require 'reth/jsonrpc/service'
13
+ require 'reth/jsonrpc/app'
@@ -0,0 +1,79 @@
1
+ module Reth
2
+ module JSONRPC
3
+
4
+ class App < Sinatra::Base
5
+
6
+ configure do
7
+ enable :logging
8
+ end
9
+
10
+ CORS_ORIGIN = "http://localhost:8080"
11
+
12
+ options "*" do
13
+ response.headers["Allow"] = "POST,OPTIONS"
14
+ response.headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept"
15
+ response.headers["Access-Control-Allow-Origin"] = "http://localhost:8080"
16
+ response.headers["Access-Control-Allow-Methods"] = "POST"
17
+
18
+ 200
19
+ end
20
+
21
+ post '/' do
22
+ response.headers["Access-Control-Allow-Origin"] = CORS_ORIGIN
23
+
24
+ begin
25
+ data = JSON.parse request.body.read
26
+ puts "Params: #{data.inspect}"
27
+
28
+ result = if data.instance_of?(Array)
29
+ data.map {|d| dispatch d }
30
+ else
31
+ dispatch data
32
+ end
33
+
34
+ json result
35
+ rescue JSON::ParserError
36
+ puts $!
37
+ puts $!.backtrace[0,10].join("\n")
38
+ json jsonrpc: '2.0', error: $!
39
+ end
40
+ end
41
+
42
+ def initialize(node)
43
+ @node = node
44
+
45
+ @default_block = 'latest'
46
+ @default_address = Account.test_accounts.keys.first
47
+ @default_startgas = 500 * 1000
48
+ @default_gas_price = 60.shannon
49
+
50
+ super()
51
+ end
52
+
53
+ private
54
+
55
+ include Handler
56
+
57
+ def dispatch(data)
58
+ # TODO: filter injection, validate method names
59
+ result = send :"handle_#{data['method']}", *data['params']
60
+
61
+ {jsonrpc: data['jsonrpc'], id: data['id'], result: result}
62
+ rescue NoMethodError
63
+ if $!.message =~ /handle_([a-zA-Z_]+)/
64
+ {jsonrpc: '2.0', id: data['id'], error: "jsonrpc method not defined: #{$1}"}
65
+ else
66
+ puts $!
67
+ puts $!.backtrace[0,10].join("\n")
68
+ {jsonrpc: data['jsonrpc'], id: data['id'], error: $!}
69
+ end
70
+ rescue
71
+ puts $!
72
+ puts $!.backtrace[0,10].join("\n")
73
+ {jsonrpc: data['jsonrpc'], id: data['id'], error: $!}
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,288 @@
1
+ module Reth
2
+ module JSONRPC
3
+
4
+ class Filter
5
+ class <<self
6
+ def next_id
7
+ @next_id ||= 0
8
+ @next_id += 1
9
+ end
10
+
11
+ def map
12
+ @map ||= {}
13
+ end
14
+
15
+ def find(id)
16
+ map[id]
17
+ end
18
+
19
+ def delete(id)
20
+ map.delete id
21
+ end
22
+
23
+ def include?(id)
24
+ map.include?(id)
25
+ end
26
+ end
27
+ end
28
+
29
+ class LogFilter
30
+
31
+ class <<self
32
+ def create(obj, chain)
33
+ f = new obj, chain
34
+ id = Filter.next_id
35
+ Filter.map[id] = f
36
+ id
37
+ end
38
+ end
39
+
40
+ include Helper
41
+
42
+ def initialize(obj, chain)
43
+ @chain = chain
44
+ @first_block, @last_block, @addresses, @topics = parse_obj obj
45
+
46
+ @last_head = @chain.head
47
+ @last_block_checked = nil
48
+
49
+ @log_dict = {}
50
+ end
51
+
52
+ def check
53
+ first, last = get_from_to @first_block, @last_block
54
+ first = [@last_head.number + 1, first].min if @first_block.is_a?(String)
55
+ raise "first must not be greater than last" unless first <= last
56
+
57
+ if @last_block_checked
58
+ first = [@last_block_checked.number + 1, first].max
59
+ return {} if first > last
60
+ end
61
+
62
+ blocks_to_check = []
63
+ (first...last).each do |n|
64
+ blocks_to_check.push @chain.index.get_block_by_number(n)
65
+ end
66
+
67
+ head = @chain.head
68
+ head_candidate = @chain.head_candidate
69
+
70
+ if last == head_candidate.number
71
+ blocks_to_check.push head_candidate
72
+ else
73
+ blocks_to_check.push @chain.get(@chain.index.get_block_by_number(last))
74
+ end
75
+
76
+ int32 = RLP::Sedes::BigEndianInt.new 32
77
+
78
+ new_logs = {}
79
+ blocks_to_check.each_with_index do |block, i|
80
+ unless [Ethereum::Block, Ethereum::CachedBlock].include?(block.class)
81
+ # must be blockhash
82
+ bloom = @chain.get_bloom block
83
+
84
+ if @addresses
85
+ pass_address_check = @addresses.any? {|addr| Ethereum::Bloom.query(bloom, addr) }
86
+ next unless pass_address_check
87
+ end
88
+
89
+ topics = (@topics || []).map {|t| int32.serialize(t) }
90
+ topic_bloom = Ethereum::Bloom.from_array topics
91
+ next if Ethereum::Bloom.combine(bloom, topic_bloom) != bloom
92
+
93
+ block = @chain.get block
94
+ end
95
+
96
+ r_idx = nil
97
+ l_idx = nil
98
+ log = nil
99
+ block.get_receipts.each_with_index do |receipt, ri|
100
+ r_idx = ri
101
+
102
+ receipt.logs.each_with_index do |_log, li|
103
+ log = _log
104
+ l_idx = li
105
+
106
+ next if @addresses && !@addresses.include?(log.address)
107
+
108
+ if @topics
109
+ topic_match = log.topics.size >= @topics.size
110
+ next unless topic_match
111
+
112
+ @topics.zip(log.topics).each do |filter_topic, log_topic|
113
+ if filter_topic && filter_topic != log_topic
114
+ topic_match = false
115
+ break
116
+ end
117
+ end
118
+ next unless topic_match
119
+ end
120
+
121
+ tx = block.get_transaction r_idx
122
+ id = Ethereum::Utils.keccak256 "#{tx.full_hash}#{l_idx}"
123
+ pending = block == head_candidate
124
+ new_logs[id] = {
125
+ log: log,
126
+ log_idx: l_idx,
127
+ block: block,
128
+ txhash: tx.full_hash,
129
+ tx_idx: r_idx
130
+ }
131
+ end
132
+ end
133
+ end
134
+
135
+ @last_block_checked = if blocks_to_check.last != head_candidate
136
+ blocks_to_check.last
137
+ else
138
+ blocks_to_check.size >= 2 ? blocks_to_check[-2] : nil
139
+ end
140
+
141
+ if @last_block_checked && ![Ethereum::Block, Ethereum::CachedBlock].include?(@last_block_checked.class)
142
+ @last_block_checked = @chain.get @last_block_checked
143
+ end
144
+
145
+ actually_new_ids = new_logs.keys - @log_dict.keys
146
+ @log_dict.merge! new_logs
147
+
148
+ actually_new_ids.map {|id| [id, new_logs[id]] }.to_h
149
+ end
150
+
151
+ def logs
152
+ check
153
+ @log_dict.values
154
+ end
155
+
156
+ def new_logs
157
+ check.values
158
+ end
159
+
160
+ def to_s
161
+ "<Filter(addressed=#{@addresses}, topics=#{@topics}, first=#{@first_block}, last=#{@last_block})>"
162
+ end
163
+
164
+ private
165
+
166
+ def parse_obj(obj)
167
+ raise ArgumentError, 'obj must be a Hash' unless obj.instance_of?(Hash)
168
+
169
+ addresses = case obj['address']
170
+ when String
171
+ [hex_to_bytes(obj['address'])]
172
+ when Array
173
+ obj['address'].map {|addr| hex_to_bytes(addr) }
174
+ when NilClass
175
+ nil
176
+ else
177
+ raise ArgumentError, "address must be String or Array of Strings"
178
+ end
179
+
180
+ topics = nil
181
+ if obj.has_key?('topics')
182
+ topics = []
183
+ obj['topics'].each do |t|
184
+ if t
185
+ topics.push(Ethereum::Utils.big_endian_to_int hex_to_bytes(t))
186
+ else
187
+ topics.push(nil)
188
+ end
189
+ end
190
+ end
191
+
192
+ from_block = decode_block_tag(obj['fromBlock'] || 'latest')
193
+ to_block = decode_block_tag(obj['toBlock'] || 'latest')
194
+
195
+ from, to = get_from_to from_block, to_block
196
+ raise ArgumentError, 'fromBlock must not be newer than toBlock' if from > to
197
+
198
+ return from_block, to_block, addresses, topics
199
+ end
200
+
201
+ def get_from_to(from_block, to_block)
202
+ block_tags = {
203
+ 'earliest' => 0,
204
+ 'latest' => @chain.head.number,
205
+ 'pending' => @chain.head_candidate.number
206
+ }
207
+ from = from_block.is_a?(Integer) ? from_block : block_tags[from_block]
208
+ to = to_block.is_a?(Integer) ? to_block : block_tags[to_block]
209
+
210
+ return from, to
211
+ end
212
+
213
+ end
214
+
215
+ class BlockFilter
216
+
217
+ class <<self
218
+ def create(chain)
219
+ f = new chain
220
+ id = Filter.next_id
221
+ Filter.map[id] = f
222
+ id
223
+ end
224
+ end
225
+
226
+ def initialize(chain)
227
+ @chain = chain
228
+ @latest_block = chain.head
229
+ end
230
+
231
+ def check
232
+ new_blocks = []
233
+ block = @chain.head
234
+
235
+ while block.number > @latest_block.number
236
+ new_blocks.push block
237
+ block = block.get_parent
238
+ end
239
+
240
+ puts "previous latest block not in current chain!" if block != @latest_block
241
+ @latest_block = new_blocks.first if new_blocks.size > 0
242
+
243
+ new_blocks.reverse
244
+ end
245
+
246
+ end
247
+
248
+ class PendingTransactionFilter
249
+
250
+ class <<self
251
+ def create(chain)
252
+ f = new chain
253
+ id = Filter.next_id
254
+ Filter.map[id] = f
255
+ id
256
+ end
257
+ end
258
+
259
+ def initialize(chain)
260
+ @chain = chain
261
+ @latest_block = @chain.head_candidate
262
+ @reported_txs = []
263
+ end
264
+
265
+ def check
266
+ head_candidate = @chain.head_candidate
267
+ pending_txs = head_candidate.get_transactions
268
+ new_txs = pending_txs.select {|tx| !@reported_txs.include?(tx.full_hash) }
269
+
270
+ block = head_candidate.get_parent
271
+ while block.number >= @latest_block.number
272
+ block.get_transactions.reverse.each do |tx|
273
+ new_txs.push(tx) unless @reported_txs.include?(tx.full_hash)
274
+ end
275
+
276
+ block = block.get_parent
277
+ end
278
+
279
+ @latest_block = head_candidate
280
+ @reported_txs = pending_txs.map(&:full_hash)
281
+
282
+ new_txs.reverse
283
+ end
284
+
285
+ end
286
+
287
+ end
288
+ end