reth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,424 @@
1
+ module Reth
2
+ module JSONRPC
3
+
4
+ module Handler
5
+ include Helper
6
+
7
+ def handle_web3_clientVersion
8
+ CLIENT_VERSION_STRING
9
+ end
10
+
11
+ def handle_web3_sha3(hex)
12
+ bytes = hex_to_bytes hex
13
+ bytes_to_hex Utils.keccak256(bytes)
14
+ end
15
+
16
+ def handle_net_version
17
+ discovery.protocol.class::VERSION
18
+ end
19
+
20
+ def handle_net_listening
21
+ peermanager.num_peers < peermanager.config.p2p.min_peers
22
+ end
23
+
24
+ def handle_net_peerCount
25
+ int_to_hex peermanager.num_peers
26
+ end
27
+
28
+ def handle_eth_protocolVersion
29
+ ETHProtocol.version
30
+ end
31
+
32
+ def handle_eth_syncing
33
+ return false unless chain.syncing?
34
+
35
+ synctask = chain.synchronizer.synctask
36
+ {
37
+ startingBlock: int_to_hex(synctask.start_block_number),
38
+ currentBlock: int_to_hex(chain.chain.head.number),
39
+ highestBlock: int_to_hex(synctask.end_block_number)
40
+ }
41
+ end
42
+
43
+ # TODO: real accounts
44
+ def handle_eth_coinbase
45
+ bytes_to_hex Ethereum::PrivateKey.new(Account.test_accounts.values.first).to_address
46
+ end
47
+
48
+ def handle_eth_mining
49
+ false
50
+ end
51
+
52
+ def handle_eth_hashrate
53
+ int_to_hex 0
54
+ end
55
+
56
+ def handle_eth_gasPrice
57
+ int_to_hex 1
58
+ end
59
+
60
+ def handle_eth_accounts
61
+ Account.test_accounts.keys
62
+ end
63
+
64
+ def handle_eth_blockNumber
65
+ int_to_hex chain.chain.head.number
66
+ end
67
+
68
+ def handle_eth_getBalance(address, block_tag=@default_block)
69
+ block = get_block decode_block_tag(block_tag)
70
+ int_to_hex block.get_balance(hex_to_bytes(address))
71
+ end
72
+
73
+ def handle_eth_getStorageAt(address, key, block_tag=@default_block)
74
+ block = get_block decode_block_tag(block_tag)
75
+ bytes_to_hex Utils.zpad_int(block.get_storage_data(hex_to_bytes(address), hex_to_int(key)))
76
+ end
77
+
78
+ def handle_eth_getTransactionCount(address, block_tag=@default_block)
79
+ block = get_block decode_block_tag(block_tag)
80
+ int_to_hex block.get_nonce(hex_to_bytes(address))
81
+ end
82
+
83
+ def handle_eth_getBlockTransactionCountByHash(blockhash)
84
+ block = get_block hex_to_bytes(blockhash)
85
+ int_to_hex block.transaction_count
86
+ end
87
+
88
+ def handle_eth_getBlockTransactionCountByNumber(number)
89
+ block = get_block hex_to_int(number)
90
+ int_to_hex block.transaction_count
91
+ end
92
+
93
+ def handle_eth_getUncleCountByBlockHash(blockhash)
94
+ block = get_block hex_to_bytes(blockhash)
95
+ int_to_hex block.uncles.size
96
+ end
97
+
98
+ def handle_eth_getUncleCountByBlockNumber(number)
99
+ block = get_block hex_to_int(number)
100
+ int_to_hex block.uncles.size
101
+ end
102
+
103
+ def handle_eth_getCode(address, block_tag=@default_block)
104
+ block = get_block decode_block_tag(block_tag)
105
+ bytes_to_hex block.get_code(hex_to_bytes(address))
106
+ end
107
+
108
+ def handle_eth_sign(address, data)
109
+ raise NotImplementedError
110
+ end
111
+
112
+ def handle_eth_sendTransaction(obj)
113
+ to = hex_to_bytes(obj['to'] || '')
114
+
115
+ startgas_hex = obj['gas'] || obj['startgas']
116
+ startgas = startgas_hex ? hex_to_int(startgas_hex) : @default_startgas
117
+
118
+ gas_price_hex = obj['gasPrice'] || obj['gasprice']
119
+ gas_price = gas_price_hex ? hex_to_int(gas_price_hex) : @default_gas_price
120
+
121
+ value = hex_to_int(obj['value'] || '')
122
+ data = hex_to_bytes(obj['data'] || '')
123
+
124
+ v = hex_to_int(obj['v'] || '')
125
+ r = hex_to_int(obj['r'] || '')
126
+ s = hex_to_int(obj['s'] || '')
127
+
128
+ nonce = obj['nonce'] ? hex_to_int(obj['nonce']) : nil
129
+ sender = hex_to_bytes(obj['from'] || @default_address)
130
+
131
+ if v > 0
132
+ raise "signed but no nonce provided" if nonce.nil?
133
+ raise "invalid signature" unless r > 0 && s > 0
134
+ else
135
+ nonce ||= chain.chain.head_candidate.get_nonce(sender)
136
+
137
+ addr = bytes_to_hex(sender)
138
+ privkey = Account.test_accounts[addr]
139
+ raise "no privkey found for address #{addr}" unless privkey
140
+ end
141
+
142
+ tx = Transaction.new nonce, gas_price, startgas, to, value, data, v, r, s
143
+ # TODO
144
+
145
+ puts "tx added: #{tx.log_dict}"
146
+ bytes_to_hex tx.full_hash
147
+ end
148
+
149
+ def handle_eth_sendRawTransaction(data)
150
+ raise NotImplementedError
151
+ end
152
+
153
+ def handle_eth_call(obj, block_tag='pending')
154
+ success, output, _, _ = tentatively_execute obj, block_tag
155
+ if success == 1
156
+ bytes_to_hex output
157
+ else
158
+ false
159
+ end
160
+ end
161
+
162
+ def handle_eth_estimateGas(obj, block_tag='pending')
163
+ _, _, block, test_block = tentatively_execute obj, block_tag
164
+ test_block.gas_used - block.gas_used
165
+ end
166
+
167
+ def handle_eth_getBlockByHash(blockhash, include_transactions)
168
+ block = get_block hex_to_bytes(blockhash)
169
+ encode_block block, include_transactions
170
+ end
171
+
172
+ def handle_eth_getBlockByNumber(block_tag, include_transactions)
173
+ block = get_block decode_block_tag(block_tag)
174
+ pending = block_tag == 'pending'
175
+ encode_block block, include_transactions, pending
176
+ end
177
+
178
+ def handle_eth_getTransactionByHash(txhash)
179
+ tx, block, index = @node.state.chain.index.get_transaction hex_to_bytes(txhash)
180
+
181
+ if @node.state.chain.in_main_branch?(block)
182
+ encode_tx tx, block, index, false
183
+ else
184
+ nil
185
+ end
186
+ rescue IndexError
187
+ puts $!
188
+ puts $!.backtrace.join("\n")
189
+ nil
190
+ end
191
+
192
+ def handle_eth_getTransactionByBlockHashAndIndex(blockhash, index)
193
+ block = get_block blockhash
194
+ i = hex_to_int index
195
+
196
+ tx = block.get_transaction i
197
+ pending = blockhash == 'pending'
198
+ encode_tx tx, block, i, pending
199
+ rescue IndexError
200
+ nil
201
+ end
202
+
203
+ def handle_eth_getTransactionReceipt(txhash)
204
+ tx, block, index = @node.state.chain.index.get_transaction hex_to_bytes(txhash)
205
+
206
+ return nil unless @node.state.chain.in_main_branch?(block)
207
+
208
+ receipt = block.get_receipt index
209
+ h = {
210
+ transactionHash: bytes_to_hex(tx.full_hash),
211
+ transactionIndex: int_to_hex(index),
212
+ blockHash: bytes_to_hex(block.full_hash),
213
+ blockNumber: int_to_hex(block.number),
214
+ cumulativeGasUsed: int_to_hex(receipt.gas_used),
215
+ contractAddress: tx.creates ? bytes_to_hex(tx.creates) : nil
216
+ }
217
+
218
+ if index == 0
219
+ h[:gasUsed] = int_to_hex(receipt.gas_used)
220
+ else
221
+ prev_receipt = block.get_receipt(index - 1)
222
+ raise "invalid previous receipt" unless prev_receipt.gas_used < receipt.gas_used
223
+ h[:gasUsed] = int_to_hex(receipt.gas_used - prev_receipt.gas_used)
224
+ end
225
+
226
+ logs = receipt.logs.each_with_index.map do |log, i|
227
+ {
228
+ log: log,
229
+ log_idx: i,
230
+ block: block,
231
+ txhash: tx.full_hash,
232
+ tx_idx: index,
233
+ pending: false
234
+ }
235
+ end
236
+ h[:logs] = encode_loglist logs
237
+
238
+ h
239
+ rescue IndexError
240
+ nil
241
+ end
242
+
243
+ def handle_eth_getUncleByBlockHashAndIndex(blockhash, index)
244
+ return nil if blockhash == 'pending'
245
+
246
+ block = get_block blockhash
247
+ i = hex_to_int index
248
+
249
+ uncle = block.uncles[i]
250
+ return nil unless uncle
251
+
252
+ encode_block uncle, false, false, true
253
+ end
254
+
255
+ def handle_eth_getUncleByBlockNumberAndIndex(block_tag, index)
256
+ return nil if block_tag == 'pending'
257
+
258
+ block = get_block decode_block_tag(block_tag)
259
+ i = hex_to_int index
260
+
261
+ uncle = block.uncles[i]
262
+ return nil unless uncle
263
+
264
+ encode_block uncle, false, false, true
265
+ end
266
+
267
+ def handle_eth_getCompilers
268
+ get_compilers.keys
269
+ end
270
+
271
+ def handle_eth_compileSolidity(code)
272
+ compiler, method = get_compilers[:solidity]
273
+ compiler.send method, code
274
+ end
275
+
276
+ def handle_eth_compileLLL(code)
277
+ compiler, method = get_compilers[:lll]
278
+ bytes_to_hex compiler.send(method, code)
279
+ end
280
+
281
+ def handle_eth_compileSerpent(code)
282
+ compiler, method = get_compilers[:serpent]
283
+ bytes_to_hex compiler.send(method, code)
284
+ end
285
+
286
+ def handle_eth_newFilter(obj)
287
+ int_to_hex LogFilter.create(obj, @node.state.chain)
288
+ end
289
+
290
+ def handle_eth_newBlockFilter
291
+ int_to_hex BlockFilter.create(@node.state.chain)
292
+ end
293
+
294
+ def handle_eth_newPendingTransactionFilter
295
+ int_to_hex PendingTransactionFilter.create(@node.state.chain)
296
+ end
297
+
298
+ def handle_eth_uninstallFilter(id)
299
+ id = hex_to_int id
300
+
301
+ if Filter.include?(id)
302
+ Filter.delete id
303
+ true
304
+ else
305
+ false
306
+ end
307
+ end
308
+
309
+ def handle_eth_getFilterChanges(id)
310
+ id = hex_to_int id
311
+ raise ArgumentError, "unknown filter id" unless Filter.include?(id)
312
+
313
+ filter = Filter.find id
314
+ if [BlockFilter,PendingTransactionFilter].include?(filter.class)
315
+ filter.check.map {|block_or_tx| bytes_to_hex block_or_tx.full_hash }
316
+ elsif filter.instance_of?(LogFilter)
317
+ encode_loglist filter.new_logs
318
+ else
319
+ raise "invalid filter"
320
+ end
321
+ end
322
+
323
+ def handle_eth_getFilterLogs(id)
324
+ id = hex_to_int id
325
+ raise ArgumentError, "unknown filter id" unless Filter.include?(id)
326
+
327
+ filter = Filter.find id
328
+ encode_loglist filter.logs
329
+ end
330
+
331
+ def handle_eth_getLogs(obj)
332
+ filter = LogFilter.new(obj, @node.state.chain)
333
+ encode_loglist filter.logs
334
+ end
335
+
336
+ def handle_eth_getWork
337
+ raise NotImplementedError
338
+ end
339
+
340
+ def handle_eth_submitWork
341
+ raise NotImplementedError
342
+ end
343
+
344
+ def handle_eth_submitHashrate
345
+ raise NotImplementedError
346
+ end
347
+
348
+ def handle_db_putString(db_name, k, v)
349
+ raise NotImplementedError
350
+ end
351
+
352
+ def handle_db_getString(db_name, k)
353
+ raise NotImplementedError
354
+ end
355
+
356
+ def handle_db_putHex(db_name, k, v)
357
+ raise NotImplementedError
358
+ end
359
+
360
+ def handle_db_getHex(db_name, k)
361
+ raise NotImplementedError
362
+ end
363
+
364
+ def tentatively_execute(obj, block_tag)
365
+ raise ArgumentError, 'first parameter must be an object' unless obj.instance_of?(Hash)
366
+
367
+ raise ArgumentError, 'missing message receiver (to)' unless obj['to']
368
+ to = hex_to_bytes obj['to']
369
+
370
+ block = get_block decode_block_tag(block_tag)
371
+ snapshot_before = block.snapshot
372
+ tx_root_before = snapshot_before[:txs].root_hash
373
+
374
+ if block.has_parent?
375
+ parent = block.get_parent
376
+ test_block = Block.build_from_parent parent, block.coinbase, timestamp: block.timestamp
377
+
378
+ block.get_transactions.each do |tx|
379
+ success, output = test_block.apply_transaction tx
380
+ raise "failed to prepare test block" if success == 0
381
+ end
382
+ else
383
+ env = Env.new block.db
384
+ test_block = Block.genesis env
385
+
386
+ original = snapshot_before.dup
387
+ original.delete :txs
388
+ original = Marshal.load Marshal.dump(original) # deepcopy
389
+ original[:txs] = Ethereum::Trie.new snapshot_before[:txs].db, snapshot_before[:txs].root_hash
390
+
391
+ test_block = Block.genesis env
392
+ test_block.revert original
393
+ end
394
+
395
+ startgas = obj['gas'] ? hex_to_int(obj['gas']) : (test_block.gas_limit - test_block.gas_used)
396
+ gas_price = obj['gasPrice'] ? hex_to_int(obj['gasPrice']) : 0
397
+ value = obj['value'] ? hex_to_int(obj['value']) : 0
398
+ data = obj['data'] ? hex_to_bytes(obj['data']) : ''
399
+ sender = obj['from'] ? hex_to_bytes(obj['from']) : Ethereum::Address::ZERO
400
+
401
+ nonce = test_block.get_nonce sender
402
+ tx = Transaction.new nonce, gas_price, startgas, to, value, data
403
+ tx.sender = sender
404
+
405
+ begin
406
+ # FIXME: tx.check_low_s will raise exception if block is after homestead fork
407
+ success, output = test_block.apply_transaction tx
408
+ rescue Ethereum::InvalidTransaction
409
+ puts $!
410
+ puts $!.backtrace[0,10].join("\n")
411
+ success = 0
412
+ end
413
+
414
+ snapshot_after = block.snapshot
415
+ raise "real data should not be changed" unless snapshot_after == snapshot_before
416
+ raise "real data should not be changed" unless snapshot_after[:txs].root_hash == tx_root_before
417
+
418
+ return success, output, block, test_block
419
+ end
420
+
421
+ end
422
+
423
+ end
424
+ end
@@ -0,0 +1,156 @@
1
+ module Reth
2
+ module JSONRPC
3
+
4
+ module Helper
5
+
6
+ def chain
7
+ @node.services.chain
8
+ end
9
+
10
+ def peermanager
11
+ @node.services.peermanager
12
+ end
13
+
14
+ def discovery
15
+ @node.services.discovery
16
+ end
17
+
18
+ def bytes_to_hex(bytes)
19
+ "0x#{Utils.encode_hex(bytes)}"
20
+ end
21
+
22
+ def hex_to_bytes(hex)
23
+ hex = hex[2..-1] if hex[0,2] == '0x'
24
+ Utils.decode_hex hex
25
+ end
26
+
27
+ def int_to_hex(n)
28
+ hex = Utils.encode_hex Utils.int_to_big_endian(n)
29
+ hex = hex.gsub(/\A0+/, '')
30
+ "0x#{hex.empty? ? '0' : hex}"
31
+ end
32
+
33
+ def hex_to_int(hex)
34
+ hex = hex[2..-1] if hex[0,2] == '0x'
35
+ hex = '0' + hex if hex.size % 2 == 1 # padding left to make size even
36
+ Utils.big_endian_to_int hex_to_bytes(hex)
37
+ end
38
+
39
+ def get_ivar_value(ivar)
40
+ raise "operation failed: #{ivar.reason}" if ivar.rejected?
41
+ ivar.value
42
+ end
43
+
44
+ def get_block(id)
45
+ case id
46
+ when 'latest'
47
+ chain.chain.head
48
+ when 'earliest'
49
+ chain.chain.genesis
50
+ when 'pending'
51
+ chain.chain.head_candidate
52
+ when Integer
53
+ hash = chain.chain.index.get_block_by_number id
54
+ chain.chain.get hash
55
+ when String
56
+ id = hex_to_bytes(id) if id[0,2] == '0x'
57
+ chain.chain.get id
58
+ else
59
+ raise "unknown block id: #{id}"
60
+ end
61
+ end
62
+
63
+ def decode_block_tag(tag)
64
+ return tag if tag.nil?
65
+ return tag if %w(latest earliest pending).include?(tag)
66
+ return hex_to_int(tag)
67
+ end
68
+
69
+ def encode_block(block, include_transactions=false, pending=false, is_header=false)
70
+ raise ArgumentError, "cannot include transactions for header" if include_transactions && is_header
71
+
72
+ h = {
73
+ number: pending ? nil : int_to_hex(block.number),
74
+ hash: pending ? nil : bytes_to_hex(block.full_hash),
75
+ parentHash: bytes_to_hex(block.prevhash),
76
+ nonce: pending ? nil : bytes_to_hex(block.nonce),
77
+ sha3Uncles: bytes_to_hex(block.uncles_hash),
78
+ logsBloom: pending ? nil : bytes_to_hex(Utils.int_to_big_endian(block.bloom)),
79
+ transactionsRoot: bytes_to_hex(block.tx_list_root),
80
+ stateRoot: bytes_to_hex(block.state_root),
81
+ miner: pending ? nil : bytes_to_hex(block.coinbase),
82
+ difficulty: int_to_hex(block.difficulty),
83
+ extraData: bytes_to_hex(block.extra_data),
84
+ gasLimit: int_to_hex(block.gas_limit),
85
+ gasUsed: int_to_hex(block.gas_used),
86
+ timestamp: int_to_hex(block.timestamp)
87
+ }
88
+
89
+ unless is_header
90
+ h[:totalDifficulty] = int_to_hex(block.chain_difficulty)
91
+ h[:size] = int_to_hex(RLP.encode(block).size)
92
+ h[:uncles] = block.uncles.map {|u| bytes_to_hex(u.full_hash) }
93
+
94
+ if include_transactions
95
+ h[:transactions] = block.get_transactions.each_with_index.map {|tx, i| encode_tx(tx, block, i, pending) }
96
+ else
97
+ h[:transactions] = block.get_transactions.map {|tx| bytes_to_hex(tx.full_hash) }
98
+ end
99
+ end
100
+
101
+ h
102
+ end
103
+
104
+ def encode_tx(transaction, block, i, pending)
105
+ {
106
+ hash: bytes_to_hex(transaction.full_hash),
107
+ nonce: int_to_hex(transaction.nonce),
108
+ blockHash: bytes_to_hex(block.full_hash),
109
+ blockNumber: pending ? nil : int_to_hex(block.number),
110
+ transactionIndex: int_to_hex(i),
111
+ from: bytes_to_hex(transaction.sender),
112
+ to: bytes_to_hex(transaction.to),
113
+ value: int_to_hex(transaction.value),
114
+ gasPrice: int_to_hex(transaction.gasprice),
115
+ gas: int_to_hex(transaction.startgas),
116
+ input: bytes_to_hex(transaction.data)
117
+ }
118
+ end
119
+
120
+ def encode_loglist(logs)
121
+ logs.map do |l|
122
+ {
123
+ logIndex: l[:pending] ? nil : int_to_hex(l[:log_idx]),
124
+ transactionIndex: l[:pending] ? nil : int_to_hex(l[:tx_idx]),
125
+ transactionHash: l[:pending] ? nil : bytes_to_hex(l[:txhash]),
126
+ blockHash: l[:pending] ? nil : bytes_to_hex(l[:block].full_hash),
127
+ blockNumber: l[:pending] ? nil : int_to_hex(l[:block].number),
128
+ address: bytes_to_hex(l[:log].address),
129
+ data: bytes_to_hex(l[:log].data),
130
+ topics: l[:log].topics.map {|t| bytes_to_hex Utils.zpad_int(t) },
131
+ type: l[:pending] ? 'pending' : 'mined'
132
+ }
133
+ end
134
+ end
135
+
136
+ def get_compilers
137
+ return @compilers if @compilers
138
+
139
+ @compilers = {}
140
+
141
+ if serpent = Ethereum::Tester::Language.all[:serpent]
142
+ @compilers[:serpent] = [serpent, :compile]
143
+ @compilers[:lll] = [serpent, :compile_lll]
144
+ end
145
+
146
+ if solidity = Ethereum::Tester::Language.all[:solidity]
147
+ @compilers[:solidity] = [solidity, :compile_rich]
148
+ end
149
+
150
+ @compilers
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+ end