web3ethereum 1.0.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.
data/lib/web3/eth.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "web3/eth/version"
2
+ require "web3/eth/abi/abi_coder"
3
+ require "web3/eth/utility"
4
+ require "web3/eth/block"
5
+ require "web3/eth/transaction"
6
+ require "web3/eth/contract"
7
+ require "web3/eth/call_trace"
8
+ require "web3/eth/log"
9
+ require "web3/eth/transaction_receipt"
10
+ require "web3/eth/eth_module"
11
+ require "web3/eth/trace_module"
12
+ require "web3/eth/etherscan"
13
+ require "web3/eth/rpc"
@@ -0,0 +1,375 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ require 'web3/eth/abi/type'
4
+ require 'web3/eth/abi/constant'
5
+ require 'web3/eth/abi/exceptions'
6
+ require 'web3/eth/abi/utils'
7
+
8
+ module Web3::Eth::Abi
9
+
10
+ ##
11
+ # Contract ABI encoding and decoding.
12
+ #
13
+ # @see https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
14
+ #
15
+ module AbiCoder
16
+
17
+ extend self
18
+
19
+ include Constant
20
+
21
+ class EncodingError < StandardError; end
22
+ class DecodingError < StandardError; end
23
+ class ValueOutOfBounds < ValueError; end
24
+
25
+ ##
26
+ # Encodes multiple arguments using the head/tail mechanism.
27
+ #
28
+ def encode_abi(types, args)
29
+ parsed_types = types.map {|t| Type.parse(t) }
30
+
31
+ head_size = (0...args.size)
32
+ .map {|i| parsed_types[i].size || 32 }
33
+ .reduce(0, &:+)
34
+
35
+ head, tail = '', ''
36
+ args.each_with_index do |arg, i|
37
+ if parsed_types[i].dynamic?
38
+ head += encode_type(Type.size_type, head_size + tail.size)
39
+ tail += encode_type(parsed_types[i], arg)
40
+ else
41
+ head += encode_type(parsed_types[i], arg)
42
+ end
43
+ end
44
+
45
+ "#{head}#{tail}"
46
+ end
47
+ alias :encode :encode_abi
48
+
49
+ ##
50
+ # Encodes a single value (static or dynamic).
51
+ #
52
+ # @param type [Ethereum::ABI::Type] value type
53
+ # @param arg [Object] value
54
+ #
55
+ # @return [String] encoded bytes
56
+ #
57
+ def encode_type(type, arg)
58
+ if %w(string bytes).include?(type.base) && type.sub.empty?
59
+ encode_primitive_type type, arg
60
+ elsif type.dynamic?
61
+ raise ArgumentError, "arg must be an array" unless arg.instance_of?(Array)
62
+
63
+ head, tail = '', ''
64
+ if type.dims.last == 0
65
+ head += encode_type(Type.size_type, arg.size)
66
+ else
67
+ raise ArgumentError, "Wrong array size: found #{arg.size}, expecting #{type.dims.last}" unless arg.size == type.dims.last
68
+ end
69
+
70
+ sub_type = type.subtype
71
+ sub_size = type.subtype.size
72
+ arg.size.times do |i|
73
+ if sub_size.nil?
74
+ head += encode_type(Type.size_type, 32*arg.size + tail.size)
75
+ tail += encode_type(sub_type, arg[i])
76
+ else
77
+ head += encode_type(sub_type, arg[i])
78
+ end
79
+ end
80
+
81
+ "#{head}#{tail}"
82
+ else # static type
83
+ if type.dims.empty?
84
+ encode_primitive_type type, arg
85
+ else
86
+ arg.map {|x| encode_type(type.subtype, x) }.join
87
+ end
88
+ end
89
+ end
90
+
91
+ def encode_primitive_type(type, arg)
92
+ case type.base
93
+ when 'uint'
94
+ begin
95
+ real_size = type.sub.to_i
96
+ i = get_uint arg
97
+
98
+ raise ValueOutOfBounds, arg unless i >= 0 && i < 2**real_size
99
+ Utils.zpad_int i
100
+ rescue EncodingError
101
+ raise ValueOutOfBounds, arg
102
+ end
103
+ when 'bool'
104
+ raise ArgumentError, "arg is not bool: #{arg}" unless arg.instance_of?(TrueClass) || arg.instance_of?(FalseClass)
105
+ Utils.zpad_int(arg ? 1 : 0)
106
+ when 'int'
107
+ begin
108
+ real_size = type.sub.to_i
109
+ i = get_int arg
110
+
111
+ raise ValueOutOfBounds, arg unless i >= -2**(real_size-1) && i < 2**(real_size-1)
112
+ Utils.zpad_int(i % 2**type.sub.to_i)
113
+ rescue EncodingError
114
+ raise ValueOutOfBounds, arg
115
+ end
116
+ when 'ufixed'
117
+ high, low = type.sub.split('x').map(&:to_i)
118
+
119
+ raise ValueOutOfBounds, arg unless arg >= 0 && arg < 2**high
120
+ Utils.zpad_int((arg * 2**low).to_i)
121
+ when 'fixed'
122
+ high, low = type.sub.split('x').map(&:to_i)
123
+
124
+ raise ValueOutOfBounds, arg unless arg >= -2**(high - 1) && arg < 2**(high - 1)
125
+
126
+ i = (arg * 2**low).to_i
127
+ Utils.zpad_int(i % 2**(high+low))
128
+ when 'string'
129
+ if arg.encoding.name == 'UTF-8'
130
+ arg = arg.b
131
+ else
132
+ begin
133
+ arg.unpack('U*')
134
+ rescue ArgumentError
135
+ raise ValueError, "string must be UTF-8 encoded"
136
+ end
137
+ end
138
+
139
+ if type.sub.empty? # variable length type
140
+ raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
141
+ size = Utils.zpad_int arg.size
142
+ value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
143
+ "#{size}#{value}"
144
+ else # fixed length type
145
+ sub = type.sub.to_i
146
+ raise ValueOutOfBounds, "invalid string length #{sub}" if arg.size > sub
147
+ raise ValueOutOfBounds, "invalid string length #{sub}" if sub < 0 || sub > 32
148
+ Utils.rpad(arg, BYTE_ZERO, 32)
149
+ end
150
+ when 'bytes'
151
+ raise EncodingError, "Expecting string: #{arg}" unless arg.instance_of?(String)
152
+ arg = arg.b
153
+
154
+ if type.sub.empty? # variable length type
155
+ raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
156
+ size = Utils.zpad_int arg.size
157
+ value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
158
+ "#{size}#{value}"
159
+ else # fixed length type
160
+ sub = type.sub.to_i
161
+ raise ValueOutOfBounds, "invalid bytes length #{sub}" if arg.size > sub
162
+ raise ValueOutOfBounds, "invalid bytes length #{sub}" if sub < 0 || sub > 32
163
+ Utils.rpad(arg, BYTE_ZERO, 32)
164
+ end
165
+ when 'hash'
166
+ size = type.sub.to_i
167
+ raise EncodingError, "too long: #{arg}" unless size > 0 && size <= 32
168
+
169
+ if arg.is_a?(Integer)
170
+ Utils.zpad_int(arg)
171
+ elsif arg.size == size
172
+ Utils.zpad arg, 32
173
+ elsif arg.size == size * 2
174
+ Utils.zpad_hex arg
175
+ else
176
+ raise EncodingError, "Could not parse hash: #{arg}"
177
+ end
178
+ when 'address'
179
+ if arg.is_a?(Integer)
180
+ Utils.zpad_int arg
181
+ elsif arg.size == 20
182
+ Utils.zpad arg, 32
183
+ elsif arg.size == 40
184
+ Utils.zpad_hex arg
185
+ elsif arg.size == 42 && arg[0,2] == '0x'
186
+ Utils.zpad_hex arg[2..-1]
187
+ else
188
+ raise EncodingError, "Could not parse address: #{arg}"
189
+ end
190
+ else
191
+ raise EncodingError, "Unhandled type: #{type.base} #{type.sub}"
192
+ end
193
+ end
194
+
195
+ ##
196
+ # Decodes multiple arguments using the head/tail mechanism.
197
+ #
198
+ def decode_abi(types, data)
199
+ parsed_types = types.map {|t| Type.parse(t) }
200
+
201
+ outputs = [nil] * types.size
202
+ start_positions = [nil] * types.size + [data.size]
203
+
204
+ # TODO: refactor, a reverse iteration will be better
205
+ pos = 0
206
+ parsed_types.each_with_index do |t, i|
207
+ # If a type is static, grab the data directly, otherwise record its
208
+ # start position
209
+ if t.dynamic?
210
+ start_positions[i] = Utils.big_endian_to_int(data[pos, 32])
211
+
212
+ j = i - 1
213
+ while j >= 0 && start_positions[j].nil?
214
+ start_positions[j] = start_positions[i]
215
+ j -= 1
216
+ end
217
+
218
+ pos += 32
219
+ else
220
+ outputs[i] = data[pos, t.size]
221
+ pos += t.size
222
+ end
223
+ end
224
+
225
+ # We add a start position equal to the length of the entire data for
226
+ # convenience.
227
+ j = types.size - 1
228
+ while j >= 0 && start_positions[j].nil?
229
+ start_positions[j] = start_positions[types.size]
230
+ j -= 1
231
+ end
232
+
233
+ # raise DecodingError, "Not enough data for head" unless pos <= data.size
234
+
235
+ parsed_types.each_with_index do |t, i|
236
+ if t.dynamic?
237
+ offset, next_offset = start_positions[i, 2]
238
+ outputs[i] = data[offset...next_offset]
239
+ end
240
+ end
241
+
242
+ parsed_types.zip(outputs).map {|(type, out)| decode_type(type, out) }
243
+ end
244
+ alias :decode :decode_abi
245
+
246
+ def decode_typed_data type_name, data
247
+ decode_primitive_type Type.parse(type_name), data
248
+ end
249
+
250
+ def decode_type(type, arg)
251
+ if %w(string bytes).include?(type.base) && type.sub.empty?
252
+ l = Utils.big_endian_to_int arg[0,32]
253
+ data = arg[32..-1]
254
+ data[0, l]
255
+ elsif type.dynamic?
256
+ l = Utils.big_endian_to_int arg[0,32]
257
+ subtype = type.subtype
258
+
259
+ if subtype.dynamic?
260
+ raise DecodingError, "Not enough data for head" unless arg.size >= 32 + 32*l
261
+
262
+ start_positions = (1..l).map {|i| Utils.big_endian_to_int arg[32*i, 32] }
263
+ start_positions.push arg.size
264
+
265
+ outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
266
+
267
+ outputs.map {|out| decode_type(subtype, out) }
268
+ else
269
+ (0...l).map {|i| decode_type(subtype, arg[32 + subtype.size*i, subtype.size]) }
270
+ end
271
+ elsif !type.dims.empty? # static-sized arrays
272
+ l = type.dims.last
273
+ subtype = type.subtype
274
+
275
+ (0...l).map {|i| decode_type(subtype, arg[subtype.size*i, subtype.size]) }
276
+ else
277
+ decode_primitive_type type, arg
278
+ end
279
+ end
280
+
281
+ def decode_primitive_type(type, data)
282
+ case type.base
283
+ when 'address'
284
+ Utils.encode_hex data[12..-1]
285
+ when 'string', 'bytes'
286
+ if type.sub.empty? # dynamic
287
+ if data.length==32
288
+ data[0..32]
289
+ else
290
+ size = Utils.big_endian_to_int data[0,32]
291
+ data[32..-1][0,size]
292
+ end
293
+ else # fixed
294
+ data[0, type.sub.to_i]
295
+ end
296
+ when 'hash'
297
+ data[(32 - type.sub.to_i), type.sub.to_i]
298
+ when 'uint'
299
+ Utils.big_endian_to_int data
300
+ when 'int'
301
+ u = Utils.big_endian_to_int data
302
+ u >= 2**(type.sub.to_i-1) ? (u - 2**type.sub.to_i) : u
303
+ when 'ufixed'
304
+ high, low = type.sub.split('x').map(&:to_i)
305
+ Utils.big_endian_to_int(data) * 1.0 / 2**low
306
+ when 'fixed'
307
+ high, low = type.sub.split('x').map(&:to_i)
308
+ u = Utils.big_endian_to_int data
309
+ i = u >= 2**(high+low-1) ? (u - 2**(high+low)) : u
310
+ i * 1.0 / 2**low
311
+ when 'bool'
312
+ data[-1] == BYTE_ONE
313
+ else
314
+ raise DecodingError, "Unknown primitive type: #{type.base}"
315
+ end
316
+ end
317
+
318
+ private
319
+
320
+ def get_uint(n)
321
+ case n
322
+ when Integer
323
+ raise EncodingError, "Number out of range: #{n}" if n > UINT_MAX || n < UINT_MIN
324
+ n
325
+ when String
326
+ i = if n.size == 40
327
+ Utils.decode_hex(n)
328
+ elsif n.size <= 32
329
+ n
330
+ else
331
+ raise EncodingError, "String too long: #{n}"
332
+ end
333
+ i = Utils.big_endian_to_int i
334
+
335
+ raise EncodingError, "Number out of range: #{i}" if i > UINT_MAX || i < UINT_MIN
336
+ i
337
+ when true
338
+ 1
339
+ when false, nil
340
+ 0
341
+ else
342
+ raise EncodingError, "Cannot decode uint: #{n}"
343
+ end
344
+ end
345
+
346
+ def get_int(n)
347
+ case n
348
+ when Integer
349
+ raise EncodingError, "Number out of range: #{n}" if n > INT_MAX || n < INT_MIN
350
+ n
351
+ when String
352
+ i = if n.size == 40
353
+ Utils.decode_hex(n)
354
+ elsif n.size <= 32
355
+ n
356
+ else
357
+ raise EncodingError, "String too long: #{n}"
358
+ end
359
+ i = Utils.big_endian_to_int i
360
+
361
+ i = i > INT_MAX ? (i-TT256) : i
362
+ raise EncodingError, "Number out of range: #{i}" if i > INT_MAX || i < INT_MIN
363
+ i
364
+ when true
365
+ 1
366
+ when false, nil
367
+ 0
368
+ else
369
+ raise EncodingError, "Cannot decode int: #{n}"
370
+ end
371
+ end
372
+
373
+ end
374
+
375
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ module Web3::Eth::Abi
4
+ module Constant
5
+
6
+ BYTE_EMPTY = "".freeze
7
+ BYTE_ZERO = "\x00".freeze
8
+ BYTE_ONE = "\x01".freeze
9
+
10
+ TT32 = 2**32
11
+ TT40 = 2**40
12
+ TT160 = 2**160
13
+ TT256 = 2**256
14
+ TT64M1 = 2**64 - 1
15
+
16
+ UINT_MAX = 2**256 - 1
17
+ UINT_MIN = 0
18
+ INT_MAX = 2**255 - 1
19
+ INT_MIN = -2**255
20
+
21
+ HASH_ZERO = ("\x00"*32).freeze
22
+
23
+ PUBKEY_ZERO = ("\x00"*32).freeze
24
+ PRIVKEY_ZERO = ("\x00"*32).freeze
25
+ PRIVKEY_ZERO_HEX = ('0'*64).freeze
26
+
27
+ CONTRACT_CODE_SIZE_LIMIT = 0x6000
28
+
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ module Web3::Eth::Abi
4
+
5
+ class DeprecatedError < StandardError; end
6
+ class ChecksumError < StandardError; end
7
+ class FormatError < StandardError; end
8
+ class ValidationError < StandardError; end
9
+ class ValueError < StandardError; end
10
+ class AssertError < StandardError; end
11
+
12
+ class UnknownParentError < StandardError; end
13
+ class InvalidBlock < ValidationError; end
14
+ class InvalidUncles < ValidationError; end
15
+
16
+ class InvalidTransaction < ValidationError; end
17
+ class UnsignedTransactionError < InvalidTransaction; end
18
+ class InvalidNonce < InvalidTransaction; end
19
+ class InsufficientStartGas < InvalidTransaction; end
20
+ class InsufficientBalance < InvalidTransaction; end
21
+ class BlockGasLimitReached < InvalidTransaction; end
22
+
23
+ class InvalidSPVProof < ValidationError; end
24
+
25
+ class ContractCreationFailed < StandardError; end
26
+ class TransactionFailed < StandardError; end
27
+
28
+ end