ruby-ethereum 0.9.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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +40 -0
  4. data/lib/ethereum.rb +53 -0
  5. data/lib/ethereum/abi.rb +333 -0
  6. data/lib/ethereum/abi/contract_translator.rb +174 -0
  7. data/lib/ethereum/abi/type.rb +117 -0
  8. data/lib/ethereum/account.rb +72 -0
  9. data/lib/ethereum/address.rb +60 -0
  10. data/lib/ethereum/base_convert.rb +53 -0
  11. data/lib/ethereum/block.rb +1311 -0
  12. data/lib/ethereum/block_header.rb +211 -0
  13. data/lib/ethereum/bloom.rb +83 -0
  14. data/lib/ethereum/cached_block.rb +36 -0
  15. data/lib/ethereum/chain.rb +400 -0
  16. data/lib/ethereum/constant.rb +26 -0
  17. data/lib/ethereum/core_ext/array/safe_slice.rb +18 -0
  18. data/lib/ethereum/core_ext/module/lru_cache.rb +20 -0
  19. data/lib/ethereum/core_ext/numeric/denominations.rb +45 -0
  20. data/lib/ethereum/core_ext/object/truth.rb +47 -0
  21. data/lib/ethereum/db.rb +6 -0
  22. data/lib/ethereum/db/base_db.rb +9 -0
  23. data/lib/ethereum/db/ephem_db.rb +63 -0
  24. data/lib/ethereum/db/overlay_db.rb +72 -0
  25. data/lib/ethereum/db/refcount_db.rb +188 -0
  26. data/lib/ethereum/env.rb +64 -0
  27. data/lib/ethereum/ethash.rb +78 -0
  28. data/lib/ethereum/ethash_ruby.rb +38 -0
  29. data/lib/ethereum/ethash_ruby/cache.rb +47 -0
  30. data/lib/ethereum/ethash_ruby/hashimoto.rb +75 -0
  31. data/lib/ethereum/ethash_ruby/utils.rb +53 -0
  32. data/lib/ethereum/exceptions.rb +28 -0
  33. data/lib/ethereum/external_call.rb +173 -0
  34. data/lib/ethereum/fast_rlp.rb +81 -0
  35. data/lib/ethereum/fast_vm.rb +625 -0
  36. data/lib/ethereum/fast_vm/call_data.rb +44 -0
  37. data/lib/ethereum/fast_vm/message.rb +29 -0
  38. data/lib/ethereum/fast_vm/state.rb +25 -0
  39. data/lib/ethereum/ffi/openssl.rb +390 -0
  40. data/lib/ethereum/index.rb +97 -0
  41. data/lib/ethereum/log.rb +43 -0
  42. data/lib/ethereum/miner.rb +84 -0
  43. data/lib/ethereum/opcodes.rb +131 -0
  44. data/lib/ethereum/private_key.rb +92 -0
  45. data/lib/ethereum/pruning_trie.rb +28 -0
  46. data/lib/ethereum/public_key.rb +88 -0
  47. data/lib/ethereum/receipt.rb +53 -0
  48. data/lib/ethereum/secp256k1.rb +58 -0
  49. data/lib/ethereum/secure_trie.rb +49 -0
  50. data/lib/ethereum/sedes.rb +42 -0
  51. data/lib/ethereum/special_contract.rb +95 -0
  52. data/lib/ethereum/spv.rb +79 -0
  53. data/lib/ethereum/spv/proof.rb +31 -0
  54. data/lib/ethereum/spv/proof_constructor.rb +19 -0
  55. data/lib/ethereum/spv/proof_verifier.rb +24 -0
  56. data/lib/ethereum/tester.rb +14 -0
  57. data/lib/ethereum/tester/abi_contract.rb +65 -0
  58. data/lib/ethereum/tester/fixture.rb +31 -0
  59. data/lib/ethereum/tester/language.rb +30 -0
  60. data/lib/ethereum/tester/log_recorder.rb +13 -0
  61. data/lib/ethereum/tester/solidity_wrapper.rb +144 -0
  62. data/lib/ethereum/tester/state.rb +194 -0
  63. data/lib/ethereum/transaction.rb +196 -0
  64. data/lib/ethereum/transient_trie.rb +28 -0
  65. data/lib/ethereum/trie.rb +549 -0
  66. data/lib/ethereum/trie/nibble_key.rb +184 -0
  67. data/lib/ethereum/utils.rb +191 -0
  68. data/lib/ethereum/version.rb +5 -0
  69. data/lib/ethereum/vm.rb +606 -0
  70. data/lib/ethereum/vm/call_data.rb +40 -0
  71. data/lib/ethereum/vm/message.rb +30 -0
  72. data/lib/ethereum/vm/state.rb +25 -0
  73. metadata +284 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e32eed4ba8a02a07df210841ba2b97ed3c80c646
4
+ data.tar.gz: d450dd581d2be8517fa2bc7a14d67179db61bef1
5
+ SHA512:
6
+ metadata.gz: 2d4f89154d6eb1962d5a1d5583736bca7d9e65ac6bf63e0f29ad0e1731db66e033f7f5d757a784d6563d93ba972dc13df9803e8e108963ad15dc1734d5e3c911
7
+ data.tar.gz: e9e3cfac56e2fa4d6e076a8c75fe7c248dd8ef21844d522d4ac2d5e08477dd812df94e284b97cb7ea2efabc13a2d0a3bd2fed5787a62cd6b4525791bfc993c6e
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jan Xie
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # ruby-ethereum
2
+
3
+ A Ruby implementation of [Ethereum](https://ethereum.org).
4
+
5
+ ## Install Secp256k1
6
+
7
+ ```
8
+ git clone git@github.com:bitcoin/bitcoin.git
9
+ git checkout v0.11.2
10
+
11
+ ./autogen.sh
12
+ ./configure
13
+ make
14
+ sudo make install
15
+ ```
16
+
17
+ ## Caveats
18
+
19
+ ### Increase Ruby Stack Size Limit
20
+
21
+ Or some tests will fail because the default stack size cannot hold a maximum (1024) levels
22
+ deep VM stack.
23
+
24
+ Set `RUBY_THREAD_VM_STACK_SIZE` in your shell/environment:
25
+
26
+ ```
27
+ export RUBY_THREAD_VM_STACK_SIZE=104857600 # 100M, 100 times default
28
+ ```
29
+
30
+ ## License
31
+
32
+ [MIT License](LICENSE)
33
+
34
+ ## TODO
35
+
36
+ * optimize memory foot print
37
+ * add pruning trie
38
+ * refactor abi types
39
+ * refactor trie node types
40
+ * review `db.commit_refcount_changes` usage
data/lib/ethereum.rb ADDED
@@ -0,0 +1,53 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ require 'rlp'
4
+ require 'block_logger'
5
+
6
+ module Ethereum
7
+ Logger = BlockLogger
8
+ end
9
+
10
+ Dir[File.expand_path('../ethereum/core_ext/**/*.rb', __FILE__)].each {|path| require path }
11
+
12
+ require 'ethereum/constant'
13
+ require 'ethereum/exceptions'
14
+ require 'ethereum/utils'
15
+
16
+ require 'ethereum/base_convert'
17
+ require 'ethereum/private_key'
18
+ require 'ethereum/public_key'
19
+ require 'ethereum/secp256k1'
20
+
21
+ require 'ethereum/abi'
22
+ require 'ethereum/fast_rlp'
23
+ require 'ethereum/db'
24
+ require 'ethereum/trie'
25
+ require 'ethereum/pruning_trie'
26
+ require 'ethereum/secure_trie'
27
+ require 'ethereum/transient_trie'
28
+ require 'ethereum/bloom'
29
+ require 'ethereum/spv'
30
+
31
+ require 'ethereum/ethash'
32
+ require 'ethereum/miner'
33
+
34
+ require 'ethereum/address'
35
+ require 'ethereum/special_contract'
36
+ require 'ethereum/env'
37
+
38
+ require 'ethereum/opcodes'
39
+ require 'ethereum/external_call'
40
+ require 'ethereum/fast_vm'
41
+ require 'ethereum/vm'
42
+ require 'ethereum/sedes'
43
+ require 'ethereum/log'
44
+ require 'ethereum/receipt'
45
+ require 'ethereum/transaction'
46
+ require 'ethereum/block_header'
47
+ require 'ethereum/account'
48
+ require 'ethereum/block'
49
+ require 'ethereum/cached_block'
50
+ require 'ethereum/index'
51
+ require 'ethereum/chain'
52
+
53
+ require 'ethereum/tester'
@@ -0,0 +1,333 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ require 'ethereum/abi/type'
4
+ require 'ethereum/abi/contract_translator'
5
+
6
+ module Ethereum
7
+
8
+ ##
9
+ # Contract ABI encoding and decoding.
10
+ #
11
+ # @see https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
12
+ #
13
+ module ABI
14
+
15
+ extend self
16
+
17
+ include Constant
18
+
19
+ class EncodingError < StandardError; end
20
+ class DecodingError < StandardError; end
21
+ class ValueOutOfBounds < StandardError; end
22
+
23
+ ##
24
+ # Encodes multiple arguments using the head/tail mechanism.
25
+ #
26
+ def encode_abi(types, args)
27
+ parsed_types = types.map {|t| Type.parse(t) }
28
+
29
+ head_size = (0...args.size)
30
+ .map {|i| parsed_types[i].size || 32 }
31
+ .reduce(0, &:+)
32
+
33
+ head, tail = '', ''
34
+ args.each_with_index do |arg, i|
35
+ if parsed_types[i].dynamic?
36
+ head += encode_type(Type.size_type, head_size + tail.size)
37
+ tail += encode_type(parsed_types[i], arg)
38
+ else
39
+ head += encode_type(parsed_types[i], arg)
40
+ end
41
+ end
42
+
43
+ "#{head}#{tail}"
44
+ end
45
+ alias :encode :encode_abi
46
+
47
+ ##
48
+ # Encodes a single value (static or dynamic).
49
+ #
50
+ # @param type [Ethereum::ABI::Type] value type
51
+ # @param arg [Object] value
52
+ #
53
+ # @return [String] encoded bytes
54
+ #
55
+ def encode_type(type, arg)
56
+ if %w(string bytes).include?(type.base) && type.sub.empty?
57
+ raise ArgumentError, "arg must be a string" unless arg.instance_of?(String)
58
+
59
+ size = encode_type Type.size_type, arg.size
60
+ padding = BYTE_ZERO * (Utils.ceil32(arg.size) - arg.size)
61
+
62
+ "#{size}#{arg}#{padding}"
63
+ elsif type.dynamic?
64
+ raise ArgumentError, "arg must be an array" unless arg.instance_of?(Array)
65
+
66
+ head, tail = '', ''
67
+ if type.dims.last == 0
68
+ head += encode_type(Type.size_type, arg.size)
69
+ else
70
+ raise ArgumentError, "Wrong array size: found #{arg.size}, expecting #{type.dims.last}" unless arg.size == type.dims.last
71
+ end
72
+
73
+ sub_type = type.subtype
74
+ sub_size = type.subtype.size
75
+ arg.size.times do |i|
76
+ if sub_size.nil?
77
+ head += encode_type(Type.size_type, 32*arg.size + tail.size)
78
+ tail += encode_type(sub_type, arg[i])
79
+ else
80
+ head += encode_type(sub_type, arg[i])
81
+ end
82
+ end
83
+
84
+ "#{head}#{tail}"
85
+ else # static type
86
+ if type.dims.empty?
87
+ encode_primitive_type type, arg
88
+ else
89
+ arg.map {|x| encode_type(type.subtype, x) }.join
90
+ end
91
+ end
92
+ end
93
+
94
+ def encode_primitive_type(type, arg)
95
+ case type.base
96
+ when 'uint'
97
+ real_size = type.sub.to_i
98
+ i = get_uint arg
99
+
100
+ raise ValueOutOfBounds, arg unless i >= 0 && i < 2**real_size
101
+ Utils.zpad_int i
102
+ when 'bool'
103
+ raise ArgumentError, "arg is not bool: #{arg}" unless arg.instance_of?(TrueClass) || arg.instance_of?(FalseClass)
104
+ Utils.zpad_int(arg ? 1: 0)
105
+ when 'int'
106
+ real_size = type.sub.to_i
107
+ i = get_int arg
108
+
109
+ raise ValueOutOfBounds, arg unless i >= -2**(real_size-1) && i < 2**(real_size-1)
110
+ Utils.zpad_int(i % 2**type.sub.to_i)
111
+ when 'ureal', 'ufixed'
112
+ high, low = type.sub.split('x').map(&:to_i)
113
+
114
+ raise ValueOutOfBounds, arg unless arg >= 0 && arg < 2**high
115
+ Utils.zpad_int((arg * 2**low).to_i)
116
+ when 'real', 'fixed'
117
+ high, low = type.sub.split('x').map(&:to_i)
118
+
119
+ raise ValueOutOfBounds, arg unless arg >= -2**(high - 1) && arg < 2**(high - 1)
120
+
121
+ i = (arg * 2**low).to_i
122
+ Utils.zpad_int(i % 2**(high+low))
123
+ when 'string', 'bytes'
124
+ raise EncodingError, "Expecting string: #{arg}" unless arg.instance_of?(String)
125
+
126
+ if type.sub.empty? # variable length type
127
+ size = Utils.zpad_int arg.size
128
+ padding = BYTE_ZERO * (Utils.ceil32(arg.size) - arg.size)
129
+ "#{size}#{arg}#{padding}"
130
+ else # fixed length type
131
+ raise ValueOutOfBounds, arg unless arg.size <= type.sub.to_i
132
+
133
+ padding = BYTE_ZERO * (32 - arg.size)
134
+ "#{arg}#{padding}"
135
+ end
136
+ when 'hash'
137
+ size = type.sub.to_i
138
+ raise EncodingError, "too long: #{arg}" unless size > 0 && size <= 32
139
+
140
+ if arg.is_a?(Integer)
141
+ Utils.zpad_int(arg)
142
+ elsif arg.size == size
143
+ Utils.zpad arg, 32
144
+ elsif arg.size == size * 2
145
+ Utils.zpad_hex arg
146
+ else
147
+ raise EncodingError, "Could not parse hash: #{arg}"
148
+ end
149
+ when 'address'
150
+ if arg.is_a?(Integer)
151
+ Utils.zpad_int arg
152
+ elsif arg.size == 20
153
+ Utils.zpad arg, 32
154
+ elsif arg.size == 40
155
+ Utils.zpad_hex arg
156
+ elsif arg.size == 42 && arg[0,2] == '0x'
157
+ Utils.zpad_hex arg[2..-1]
158
+ else
159
+ raise EncodingError, "Could not parse address: #{arg}"
160
+ end
161
+ else
162
+ raise EncodingError, "Unhandled type: #{type.base} #{type.sub}"
163
+ end
164
+ end
165
+
166
+ ##
167
+ # Decodes multiple arguments using the head/tail mechanism.
168
+ #
169
+ def decode_abi(types, data)
170
+ parsed_types = types.map {|t| Type.parse(t) }
171
+
172
+ outputs = [nil] * types.size
173
+ start_positions = [nil] * types.size + [data.size]
174
+
175
+ # TODO: refactor, a reverse iteration will be better
176
+ pos = 0
177
+ parsed_types.each_with_index do |t, i|
178
+ # If a type is static, grab the data directly, otherwise record its
179
+ # start position
180
+ if t.dynamic?
181
+ start_positions[i] = Utils.big_endian_to_int(data[pos, 32])
182
+
183
+ j = i - 1
184
+ while j >= 0 && start_positions[j].nil?
185
+ start_positions[j] = start_positions[i]
186
+ j -= 1
187
+ end
188
+
189
+ pos += 32
190
+ else
191
+ outputs[i] = data[pos, t.size]
192
+ pos += t.size
193
+ end
194
+ end
195
+
196
+ # We add a start position equal to the length of the entire data for
197
+ # convenience.
198
+ j = types.size - 1
199
+ while j >= 0 && start_positions[j].nil?
200
+ start_positions[j] = start_positions[types.size]
201
+ j -= 1
202
+ end
203
+
204
+ raise DecodingError, "Not enough data for head" unless pos <= data.size
205
+
206
+ parsed_types.each_with_index do |t, i|
207
+ if t.dynamic?
208
+ offset, next_offset = start_positions[i, 2]
209
+ outputs[i] = data[offset...next_offset]
210
+ end
211
+ end
212
+
213
+ parsed_types.zip(outputs).map {|(type, out)| decode_type(type, out) }
214
+ end
215
+ alias :decode :decode_abi
216
+
217
+ def decode_type(type, arg)
218
+ if %w(string bytes).include?(type.base) && type.sub.empty?
219
+ l = Utils.big_endian_to_int arg[0,32]
220
+ data = arg[32..-1]
221
+
222
+ raise DecodingError, "Wrong data size for string/bytes object" unless data.size == Utils.ceil32(l)
223
+
224
+ data[0, l]
225
+ elsif type.dynamic?
226
+ l = Utils.big_endian_to_int arg[0,32]
227
+ subtype = type.subtype
228
+
229
+ if subtype.dynamic?
230
+ raise DecodingError, "Not enough data for head" unless arg.size >= 32 + 32*l
231
+
232
+ start_positions = (1..l).map {|i| Utils.big_endian_to_int arg[32*i, 32] }
233
+ start_positions.push arg.size
234
+
235
+ outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
236
+
237
+ outputs.map {|out| decode_type(subtype, out) }
238
+ else
239
+ (0...l).map {|i| decode_type(subtype, arg[32 + subtype.size*i, subtype.size]) }
240
+ end
241
+ elsif !type.dims.empty? # static-sized arrays
242
+ l = type.dims.last[0]
243
+ subtype = type.subtype
244
+
245
+ (0...l).map {|i| decode_type(subtype, arg[subtype.size*i, subtype.size]) }
246
+ else
247
+ decode_primitive_type type, arg
248
+ end
249
+ end
250
+
251
+ def decode_primitive_type(type, data)
252
+ case type.base
253
+ when 'address'
254
+ Utils.encode_hex data[12..-1]
255
+ when 'string', 'bytes'
256
+ if type.sub.empty? # dynamic
257
+ size = Utils.big_endian_to_int data[0,32]
258
+ data[32..-1][0,size]
259
+ else # fixed
260
+ data[0, type.sub.to_i]
261
+ end
262
+ when 'hash'
263
+ data[(32 - type.sub.to_i), type.sub.to_i]
264
+ when 'uint'
265
+ Utils.big_endian_to_int data
266
+ when 'int'
267
+ u = Utils.big_endian_to_int data
268
+ u >= 2**(type.sub.to_i-1) ? (u - 2**type.sub.to_i) : u
269
+ when 'ureal', 'ufixed'
270
+ high, low = type.sub.split('x').map(&:to_i)
271
+ Utils.big_endian_to_int(data) * 1.0 / 2**low
272
+ when 'real', 'fixed'
273
+ high, low = type.sub.split('x').map(&:to_i)
274
+ u = Utils.big_endian_to_int data
275
+ i = u >= 2**(high+low-1) ? (u - 2**(high+low)) : u
276
+ i * 1.0 / 2**low
277
+ when 'bool'
278
+ data[-1] == BYTE_ONE
279
+ else
280
+ raise DecodingError, "Unknown primitive type: #{type.base}"
281
+ end
282
+ end
283
+
284
+ private
285
+
286
+ def get_uint(n)
287
+ case n
288
+ when Integer
289
+ raise EncodingError, "Number out of range: #{n}" if n > UINT_MAX || n < UINT_MIN
290
+ n
291
+ when String
292
+ if n.size == 40
293
+ Utils.big_endian_to_int Utils.decode_hex(n)
294
+ elsif n.size <= 32
295
+ Utils.big_endian_to_int n
296
+ else
297
+ raise EncodingError, "String too long: #{n}"
298
+ end
299
+ when true
300
+ 1
301
+ when false, nil
302
+ 0
303
+ else
304
+ raise EncodingError, "Cannot decode uint: #{n}"
305
+ end
306
+ end
307
+
308
+ def get_int(n)
309
+ case n
310
+ when Integer
311
+ raise EncodingError, "Number out of range: #{n}" if n > INT_MAX || n < INT_MIN
312
+ n
313
+ when String
314
+ if n.size == 40
315
+ i = Utils.big_endian_to_int Utils.decode_hex(n)
316
+ elsif n.size <= 32
317
+ i = Utils.big_endian_to_int n
318
+ else
319
+ raise EncodingError, "String too long: #{n}"
320
+ end
321
+ i > INT_MAX ? (i-TT256) : i
322
+ when true
323
+ 1
324
+ when false, nil
325
+ 0
326
+ else
327
+ raise EncodingError, "Cannot decode int: #{n}"
328
+ end
329
+ end
330
+
331
+ end
332
+
333
+ end