abicoder 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,413 +0,0 @@
1
-
2
- module ABI
3
- ##
4
- # Contract ABI encoding and decoding.
5
- #
6
- # @see https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
7
- #
8
- class Codec
9
- class EncodingError < StandardError; end
10
- class DecodingError < StandardError; end
11
- class ValueError < StandardError; end
12
-
13
- class ValueOutOfBounds < ValueError; end
14
-
15
- ##
16
- # Encodes multiple arguments using the head/tail mechanism.
17
- #
18
- def encode_abi(types, args)
19
- ## for convenience check if types is a String
20
- ## otherwise assume ABI::Type already
21
- types = types.map { |type| type.is_a?( String ) ? Type.parse( type ) : type }
22
-
23
- head_size = (0...args.size)
24
- .map {|i| types[i].size || 32 }
25
- .reduce(0, &:+)
26
-
27
- head, tail = '', ''
28
- args.each_with_index do |arg, i|
29
- if types[i].dynamic?
30
- head += encode_type(Type.size_type, head_size + tail.size)
31
- tail += encode_type(types[i], arg)
32
- else
33
- head += encode_type(types[i], arg)
34
- end
35
- end
36
-
37
- "#{head}#{tail}"
38
- end
39
-
40
- ##
41
- # Encodes a single value (static or dynamic).
42
- #
43
- # @param type [ABI::Type] value type
44
- # @param arg [Object] value
45
- #
46
- # @return [String] encoded bytes
47
- #
48
- def encode_type(type, arg)
49
- if ['string', 'bytes'].include?(type.base) && type.sub.empty?
50
- encode_primitive_type type, arg
51
- elsif type.dynamic?
52
- raise ArgumentError, "arg must be an array" unless arg.instance_of?(Array)
53
-
54
- head, tail = '', ''
55
- if type.dims.last == 0
56
- head += encode_type(Type.size_type, arg.size)
57
- else
58
- raise ArgumentError, "Wrong array size: found #{arg.size}, expecting #{type.dims.last}" unless arg.size == type.dims.last
59
- end
60
-
61
- sub_type = type.subtype
62
- sub_size = type.subtype.size
63
- arg.size.times do |i|
64
- if sub_size.nil?
65
- head += encode_type(Type.size_type, 32*arg.size + tail.size)
66
- tail += encode_type(sub_type, arg[i])
67
- else
68
- head += encode_type(sub_type, arg[i])
69
- end
70
- end
71
-
72
- "#{head}#{tail}"
73
- else # static type
74
- if type.dims.empty?
75
- encode_primitive_type type, arg
76
- else
77
- arg.map {|x| encode_type(type.subtype, x) }.join
78
- end
79
- end
80
- end
81
-
82
- def encode_primitive_type(type, arg)
83
- case type.base
84
- when 'uint'
85
- begin
86
- real_size = type.sub.to_i
87
- i = get_uint arg
88
-
89
- raise ValueOutOfBounds, arg unless i >= 0 && i < 2**real_size
90
- Utils.zpad_int i
91
- rescue EncodingError
92
- raise ValueOutOfBounds, arg
93
- end
94
- when 'bool'
95
- raise ArgumentError, "arg is not bool: #{arg}" unless arg.instance_of?(TrueClass) || arg.instance_of?(FalseClass)
96
- Utils.zpad_int(arg ? 1 : 0)
97
- when 'int'
98
- begin
99
- real_size = type.sub.to_i
100
- i = get_int arg
101
-
102
- raise ValueOutOfBounds, arg unless i >= -2**(real_size-1) && i < 2**(real_size-1)
103
- Utils.zpad_int(i % 2**type.sub.to_i)
104
- rescue EncodingError
105
- raise ValueOutOfBounds, arg
106
- end
107
- when 'string'
108
- if arg.encoding.name == 'UTF-8'
109
- arg = arg.b
110
- else
111
- begin
112
- arg.unpack('U*')
113
- rescue ArgumentError
114
- raise ValueError, "string must be UTF-8 encoded"
115
- end
116
- end
117
-
118
- if type.sub.empty? # variable length type
119
- raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
120
- size = Utils.zpad_int arg.size
121
- value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
122
- "#{size}#{value}"
123
- else # fixed length type
124
- sub = type.sub.to_i
125
- raise ValueOutOfBounds, "invalid string length #{sub}" if arg.size > sub
126
- raise ValueOutOfBounds, "invalid string length #{sub}" if sub < 0 || sub > 32
127
- Utils.rpad(arg, BYTE_ZERO, 32)
128
- end
129
- when 'bytes'
130
- raise EncodingError, "Expecting string: #{arg}" unless arg.instance_of?(String)
131
- arg = arg.b
132
-
133
- if type.sub.empty? # variable length type
134
- raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
135
- size = Utils.zpad_int arg.size
136
- value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
137
- "#{size}#{value}"
138
- else # fixed length type
139
- sub = type.sub.to_i
140
- raise ValueOutOfBounds, "invalid bytes length #{sub}" if arg.size > sub
141
- raise ValueOutOfBounds, "invalid bytes length #{sub}" if sub < 0 || sub > 32
142
- Utils.rpad(arg, BYTE_ZERO, 32)
143
- end
144
- when 'address'
145
- if arg.is_a?(Integer)
146
- Utils.zpad_int arg
147
- elsif arg.size == 20
148
- Utils.zpad arg, 32
149
- elsif arg.size == 40
150
- Utils.zpad_hex arg
151
- elsif arg.size == 42 && arg[0,2] == '0x'
152
- Utils.zpad_hex arg[2..-1]
153
- else
154
- raise EncodingError, "Could not parse address: #{arg}"
155
- end
156
- else
157
- raise EncodingError, "Unhandled type: #{type.base} #{type.sub}"
158
- end
159
- end
160
-
161
-
162
- def min_data_size( types )
163
- types.size*32
164
- end
165
-
166
- ##
167
- # Decodes multiple arguments using the head/tail mechanism.
168
- #
169
- def decode_abi( types, data, raise_errors = false )
170
- ## for convenience check if types is a String
171
- ## otherwise assume ABI::Type already
172
- types = types.map { |type| type.is_a?( String ) ? Type.parse( type ) : type }
173
-
174
- outputs = [nil] * types.size
175
- start_positions = [nil] * types.size + [data.size]
176
-
177
- # TODO: refactor, a reverse iteration will be better
178
- pos = 0
179
- types.each_with_index do |t, i|
180
- # If a type is static, grab the data directly, otherwise record its
181
- # start position
182
- if t.dynamic?
183
-
184
- if raise_errors && pos>data.size-1
185
- raise DecodingError, "Position out of bounds #{pos}>#{data.size-1}"
186
- end
187
-
188
- start_positions[i] = Utils.big_endian_to_int(data[pos, 32])
189
-
190
- if raise_errors && start_positions[i]>data.size-1
191
- raise DecodingError, "Start position out of bounds #{start_positions[i]}>#{data.size-1}"
192
- end
193
-
194
- j = i - 1
195
- while j >= 0 && start_positions[j].nil?
196
- start_positions[j] = start_positions[i]
197
- j -= 1
198
- end
199
-
200
- pos += 32
201
- else
202
- outputs[i] = zero_padding data, pos, t.size, start_positions
203
- pos += t.size
204
- end
205
- end
206
-
207
- # We add a start position equal to the length of the entire data for
208
- # convenience.
209
- j = types.size - 1
210
- while j >= 0 && start_positions[j].nil?
211
- start_positions[j] = start_positions[types.size]
212
- j -= 1
213
- end
214
-
215
- if raise_errors && pos > data.size
216
- raise DecodingError, "Not enough data for head"
217
- end
218
-
219
-
220
- types.each_with_index do |t, i|
221
- if t.dynamic?
222
- offset, next_offset = start_positions[i, 2]
223
- if offset<=data.size && next_offset<=data.size
224
- outputs[i] = data[offset...next_offset]
225
- end
226
- end
227
- end
228
-
229
- if raise_errors && outputs.include?(nil)
230
- raise DecodingError, "Not all data can be parsed"
231
- end
232
-
233
- types.zip(outputs).map {|(type, out)| decode_type(type, out) }
234
- end
235
-
236
-
237
- def zero_padding( data, pos, count, start_positions )
238
- if pos >= data.size
239
- start_positions[start_positions.size-1] += count
240
- "\x00"*count
241
- elsif pos + count > data.size
242
- start_positions[start_positions.size-1] += ( count - (data.size-pos))
243
- data[pos,data.size-pos] + "\x00"*( count - (data.size-pos))
244
- else
245
- data[pos, count]
246
- end
247
- end
248
-
249
- def decode_typed_data( type_name, data )
250
- decode_primitive_type Type.parse(type_name), data
251
- end
252
-
253
- def decode_type(type, arg)
254
- return nil if arg.nil? || arg.empty?
255
- if type.kind_of?( Tuple ) && type.dims.empty?
256
- arg ? decode_abi(type.types, arg) : []
257
- elsif %w(string bytes).include?(type.base) && type.sub.empty?
258
- l = Utils.big_endian_to_int arg[0,32]
259
- data = arg[32..-1]
260
- data[0, l]
261
- elsif !type.dims.empty? && (l = type.dims.last)>0 # static-sized arrays
262
- subtype = type.subtype
263
- if subtype.dynamic?
264
- start_positions = (0...l).map {|i| Utils.big_endian_to_int(arg[32*i, 32]) }
265
- start_positions.push arg.size
266
-
267
- outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
268
-
269
- outputs.map {|out| decode_type(subtype, out) }
270
- else
271
- (0...l).map {|i| decode_type(subtype, arg[subtype.size*i, subtype.size]) }
272
- end
273
-
274
- elsif type.dynamic?
275
- l = Utils.big_endian_to_int arg[0,32]
276
- raise DecodingError, "Too long length: #{l}" if l>100000
277
- subtype = type.subtype
278
-
279
- if subtype.dynamic?
280
- raise DecodingError, "Not enough data for head" unless arg.size >= 32 + 32*l
281
-
282
- start_positions = (1..l).map {|i| 32+Utils.big_endian_to_int(arg[32*i, 32]) }
283
- start_positions.push arg.size
284
-
285
- outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
286
-
287
- outputs.map {|out| decode_type(subtype, out) }
288
- else
289
- (0...l).map {|i| decode_type(subtype, arg[32 + subtype.size*i, subtype.size]) }
290
- end
291
-
292
- else
293
- decode_primitive_type type, arg
294
- end
295
- end
296
-
297
- def decode_primitive_type(type, data)
298
- case type.base
299
- when 'address'
300
- Utils.encode_hex data[12..-1]
301
- when 'string', 'bytes'
302
- if type.sub.empty? # dynamic
303
- if data.length==32
304
- data[0..32]
305
- else
306
- size = Utils.big_endian_to_int data[0,32]
307
- data[32..-1][0,size]
308
- end
309
- else # fixed
310
- data[0, type.sub.to_i]
311
- end
312
- when 'hash'
313
- data[(32 - type.sub.to_i), type.sub.to_i]
314
- when 'uint'
315
- Utils.big_endian_to_int data
316
- when 'int'
317
- u = Utils.big_endian_to_int data
318
- u >= 2**(type.sub.to_i-1) ? (u - 2**type.sub.to_i) : u
319
- when 'ufixed'
320
- high, low = type.sub.split('x').map(&:to_i)
321
- Utils.big_endian_to_int(data) * 1.0 / 2**low
322
- when 'fixed'
323
- high, low = type.sub.split('x').map(&:to_i)
324
- u = Utils.big_endian_to_int data
325
- i = u >= 2**(high+low-1) ? (u - 2**(high+low)) : u
326
- i * 1.0 / 2**low
327
- when 'bool'
328
- data[-1] == BYTE_ONE
329
- else
330
- raise DecodingError, "Unknown primitive type: #{type.base}"
331
- end
332
- end
333
-
334
- private
335
-
336
- def get_uint(n)
337
- case n
338
- when Integer
339
- raise EncodingError, "Number out of range: #{n}" if n > UINT_MAX || n < UINT_MIN
340
- n
341
- when String
342
- i = if n.size == 40
343
- Utils.decode_hex(n)
344
- elsif n.size <= 32
345
- n
346
- else
347
- raise EncodingError, "String too long: #{n}"
348
- end
349
- i = Utils.big_endian_to_int i
350
-
351
- raise EncodingError, "Number out of range: #{i}" if i > UINT_MAX || i < UINT_MIN
352
- i
353
- when true
354
- 1
355
- when false, nil
356
- 0
357
- else
358
- raise EncodingError, "Cannot decode uint: #{n}"
359
- end
360
- end
361
-
362
- def get_int(n)
363
- case n
364
- when Integer
365
- raise EncodingError, "Number out of range: #{n}" if n > INT_MAX || n < INT_MIN
366
- n
367
- when String
368
- i = if n.size == 40
369
- Utils.decode_hex(n)
370
- elsif n.size <= 32
371
- n
372
- else
373
- raise EncodingError, "String too long: #{n}"
374
- end
375
- i = Utils.big_endian_to_int i
376
-
377
- i = i > INT_MAX ? (i-TT256) : i
378
- raise EncodingError, "Number out of range: #{i}" if i > INT_MAX || i < INT_MIN
379
- i
380
- when true
381
- 1
382
- when false, nil
383
- 0
384
- else
385
- raise EncodingError, "Cannot decode int: #{n}"
386
- end
387
- end
388
- end # class Codec
389
-
390
-
391
-
392
- def self.codec
393
- @codec ||= Codec.new
394
- end
395
-
396
- def self.encode_abi( types, args )
397
- codec.encode_abi( types, args )
398
- end
399
-
400
- def self.decode_abi( types, data, raise_errors = false )
401
- codec.decode_abi( types, data, raise_errors )
402
- end
403
-
404
- ## add alternate names
405
- ## todo/fix: change to encode / decode by default
406
- ## from encode_abi / decode_abi - why? why not?
407
- class << self
408
- alias_method :encode, :encode_abi
409
- alias_method :decode, :decode_abi
410
- end
411
-
412
- end # module ABI
413
-
data/lib/abicoder/type.rb DELETED
@@ -1,141 +0,0 @@
1
- module ABI
2
- class Type
3
-
4
- class ParseError < StandardError; end
5
-
6
- ##
7
- # Crazy regexp to seperate out base type component (eg. uint), size (eg.
8
- # 256, 128, nil), array component (eg. [], [45], nil)
9
- #
10
- BASE_TYPE_RX = /([a-z]*)
11
- ([0-9]*)
12
- ((\[[0-9]*\])*)
13
- /x
14
-
15
- def self._parse_base_type( str )
16
- _, base, sub, dimension = BASE_TYPE_RX.match( str ).to_a
17
-
18
- dims = dimension.scan( /\[[0-9]*\]/ )
19
- if dims.join != dimension
20
- raise ParseError, "Unknown characters found in array declaration"
21
- end
22
-
23
- dims = dims.map {|x| x[1...-1].to_i }
24
-
25
- [base, sub, dims]
26
- end
27
-
28
-
29
-
30
- TUPLE_TYPE_RX = /^\((.*)\)
31
- ((\[[0-9]*\])*)
32
- /x
33
-
34
- def self.parse( type )
35
- if type =~ TUPLE_TYPE_RX
36
- types = $1
37
- dims = $2.scan( /\[[0-9]*\]/ )
38
- dims = dims.map {|x| x[1...-1].to_i}
39
- return Tuple._parse( types, dims )
40
- end
41
-
42
-
43
- base, sub, dims = _parse_base_type( type )
44
-
45
- case base
46
- when 'bytes', 'string'
47
- raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub.empty? || sub.to_i <= 32
48
- when 'uint', 'int'
49
- raise ParseError, "Integer type must have numerical suffix" unless sub =~ /\A[0-9]+\z/
50
-
51
- size = sub.to_i
52
- raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256
53
- raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
54
- when 'address'
55
- raise ParseError, "Address cannot have suffix" unless sub.empty?
56
- when 'bool'
57
- raise ParseError, "Bool cannot have suffix" unless sub.empty?
58
- else
59
- puts " type: >#{type}<"
60
- raise ParseError, "Unrecognized type base: #{base}"
61
- end
62
-
63
- new( base, sub, dims )
64
- end
65
-
66
-
67
- def self.size_type
68
- @size_type ||= new( 'uint', '256' )
69
- end
70
-
71
-
72
- attr :base, :sub, :dims
73
-
74
- ##
75
- # @param base [String] base name of type, e.g. uint for uint256[4]
76
- # @param sub [String] subscript of type, e.g. 256 for uint256[4]
77
- # @param dims [Array[Integer]] dimensions of array type, e.g. [1,2,0]
78
- # for uint256[1][2][], [] for non-array type
79
- #
80
- def initialize( base, sub, dims=[] )
81
- @base = base
82
- @sub = sub
83
- @dims = dims
84
- end
85
-
86
- def ==(another_type)
87
- @base == another_type.base &&
88
- @sub == another_type.sub &&
89
- @dims == another_type.dims
90
- end
91
-
92
- ##
93
- # Get the static size of a type, or nil if dynamic.
94
- #
95
- # @return [Integer, NilClass] size of static type, or nil for dynamic type
96
- #
97
- def size
98
- @size ||= calculate_size
99
- end
100
-
101
- def calculate_size
102
- if @dims.empty?
103
- if ['string','bytes'].include?( @base ) && @sub.empty?
104
- nil
105
- else
106
- 32
107
- end
108
- else
109
- if @dims.last == 0 # note: 0 used for dynamic array []
110
- nil
111
- else
112
- subtype.dynamic? ? nil : @dims.last * subtype.size
113
- end
114
- end
115
- end
116
-
117
- def dynamic?() size.nil?; end
118
-
119
-
120
- ##
121
- # Type with one dimension lesser.
122
- #
123
- # @example
124
- # Type.parse("uint256[2][]").subtype # => Type.new('uint', '256', [2])
125
- #
126
- # @return [ABI::Type]
127
- #
128
- def subtype
129
- @subtype ||= Type.new( @base, @sub, @dims[0...-1] )
130
- end
131
-
132
-
133
- def format
134
- ## rebuild minimal type string
135
- buf = "#{@base}"
136
- buf << @sub unless @sub.empty?
137
- buf << (@dims.map {|dim| dim==0 ? '[]' : "[#{dim}]"}.join) unless @dims.empty?
138
- buf
139
- end
140
- end # class Type
141
- end # module ABI
@@ -1,106 +0,0 @@
1
- module ABI
2
-
3
-
4
- class Tuple < Type
5
-
6
- def self._parse_tuple_type( str )
7
- ## note: types assumes string WITHOUT enclosing () e.g.
8
- ## tuple(string,string,bool) => expected as "string,string,bool"
9
-
10
- depth = 0
11
- collected = []
12
- current = ''
13
-
14
- ### todo/fix: replace with a simple parser!!!
15
- ## allow () and move verbose tuple() too!!!
16
- str.each_char do |c|
17
- case c
18
- when ',' then
19
- if depth == 0
20
- collected << current
21
- current = ''
22
- else
23
- current += c
24
- end
25
- when '(' then
26
- depth += 1
27
- current += c
28
- when ')' then
29
- depth -= 1
30
- current += c
31
- else
32
- current += c
33
- end
34
- end
35
- collected << current unless current.empty?
36
-
37
- collected
38
- end
39
-
40
-
41
- ## note: use Type.parse NOT Tuple._parse
42
- ## to parse Tuple!!!
43
- def self._parse( tuple, dims=[] )
44
- ## puts " enter Tuple.parse( types: >#{tuple.inspect}<, dims: >#{dims.inspect}< )"
45
-
46
- # e.g.
47
- #=> enter Tuple.parse( types: >"string,string,bool"<, dims: >[]< )
48
- types = _parse_tuple_type( tuple )
49
- parsed_types = types.map{ |t| Type.parse( t ) }
50
-
51
- Tuple.new( parsed_types, dims )
52
- end
53
-
54
-
55
-
56
- attr_reader :types
57
-
58
- def initialize( types, dims=[] )
59
- super( 'tuple', '', dims )
60
- @types = types
61
-
62
- ## puts "tuple:"
63
- ## pp self
64
- end
65
-
66
-
67
- def ==(another_type)
68
- another_type.kind_of?(Tuple) &&
69
- @types == another_type.types &&
70
- @dims == another_type.dims
71
- end
72
-
73
- def size
74
- @size ||= calculate_size
75
- end
76
-
77
- def calculate_size
78
- if @dims.empty?
79
- s = 0
80
- @types.each do |type|
81
- ts = type.size
82
- return nil if ts.nil?
83
- s += ts
84
- end
85
- s
86
- else
87
- if @dims.last == 0 # note: 0 used for dynamic array []
88
- nil
89
- else
90
- subtype.dynamic? ? nil : @dims.last * subtype.size
91
- end
92
- end
93
- end
94
-
95
- def subtype
96
- @subtype ||= Tuple.new( types, dims[0...-1] )
97
- end
98
-
99
- def format
100
- ## rebuild minimal string
101
- buf = "(#{@types.map {|t| t.format }.join(',')})"
102
- end
103
-
104
-
105
- end # class Tuple
106
- end ## module ABI