abicoder 0.1.0 → 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.
@@ -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