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.
- 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,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
|