Module: Eth::Abi::Decoder
Overview
Provides a utility module to assist decoding ABIs.
Class Method Summary collapse
-
.primitive_type(type, data) ⇒ String
Decodes primitive types.
-
.type(type, arg) ⇒ String
Decodes a specific value, either static or dynamic.
Instance Method Summary collapse
-
#primitive_type(type, data) ⇒ String
Decodes primitive types.
-
#type(type, arg) ⇒ String
Decodes a specific value, either static or dynamic.
Class Method Details
.primitive_type(type, data) ⇒ String
Decodes primitive types.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/eth/abi/decoder.rb', line 129 def primitive_type(type, data) case type.base_type when "address" # decoded address with 0x-prefix Address.new(Util.bin_to_hex data[12..-1]).to_s.downcase when "string", "bytes" if type.sub_type.empty? size = Util.deserialize_big_endian_to_int data[0, 32] # decoded dynamic-sized array decoded = data[32..-1][0, size] decoded.force_encoding(Encoding::UTF_8) decoded else # decoded static-sized array data[0, type.sub_type.to_i] end when "hash" # decoded hash data[(32 - type.sub_type.to_i), type.sub_type.to_i] when "uint" # decoded unsigned integer Util.deserialize_big_endian_to_int data when "int" u = Util.deserialize_big_endian_to_int data i = u >= 2 ** (type.sub_type.to_i - 1) ? (u - 2 ** 256) : u # decoded integer i when "ureal", "ufixed" high, low = type.sub_type.split("x").map(&:to_i) # decoded unsigned fixed point numeric Util.deserialize_big_endian_to_int(data) * 1.0 / 2 ** low when "real", "fixed" high, low = type.sub_type.split("x").map(&:to_i) u = Util.deserialize_big_endian_to_int data i = u >= 2 ** (high + low - 1) ? (u - 2 ** (high + low)) : u # decoded fixed point numeric i * 1.0 / 2 ** low when "bool" # decoded boolean data[-1] == Constant::BYTE_ONE else raise DecodingError, "Unknown primitive type: #{type.base_type}" end end |
.type(type, arg) ⇒ String
Decodes a specific value, either static or dynamic.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/eth/abi/decoder.rb', line 33 def type(type, arg) if %w(string bytes).include?(type.base_type) and type.sub_type.empty? # Case: decoding a string/bytes if type.dimensions.empty? l = Util.deserialize_big_endian_to_int arg[0, 32] data = arg[32..-1] raise DecodingError, "Wrong data size for string/bytes object" unless data.size == Util.ceil32(l) # decoded strings and bytes data[0, l] # Case: decoding array of string/bytes else l = Util.deserialize_big_endian_to_int arg[0, 32] raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + 32 * l # Decode each element of the array (1..l).map do |i| pointer = Util.deserialize_big_endian_to_int arg[i * 32, 32] # Pointer to the size of the array's element raise DecodingError, "Offset out of bounds" if pointer < 32 * l || pointer > arg.size - 64 data_l = Util.deserialize_big_endian_to_int arg[32 + pointer, 32] # length of the element raise DecodingError, "Offset out of bounds" if pointer + 32 + Util.ceil32(data_l) > arg.size type(Type.parse(type.base_type), arg[pointer + 32, Util.ceil32(data_l) + 32]) end end elsif type.base_type == "tuple" && type.dimensions.empty? offset = 0 result = [] raise DecodingError, "Cannot decode tuples without known components" if type.components.nil? type.components.each_with_index do |c, i| if c.dynamic? pointer = Util.deserialize_big_endian_to_int arg[offset, 32] next_offset = if i + 1 < type.components.size Util.deserialize_big_endian_to_int arg[offset + 32, 32] else arg.size end raise DecodingError, "Offset out of bounds" if pointer > arg.size || next_offset > arg.size || next_offset < pointer result << type(c, arg[pointer, next_offset - pointer]) offset += 32 else size = c.size raise DecodingError, "Offset out of bounds" if offset + size > arg.size result << type(c, arg[offset, size]) offset += size end end result elsif type.dynamic? l = Util.deserialize_big_endian_to_int arg[0, 32] nested_sub = type.nested_sub if nested_sub.dynamic? raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + 32 * l offsets = (0...l).map do |i| off = Util.deserialize_big_endian_to_int arg[32 + 32 * i, 32] raise DecodingError, "Offset out of bounds" if off < 32 * l || off > arg.size - 64 off end offsets.map { |off| type(nested_sub, arg[32 + off..]) } else raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + nested_sub.size * l # decoded dynamic-sized arrays with static sub-types (0...l).map { |i| type(nested_sub, arg[32 + nested_sub.size * i, nested_sub.size]) } end elsif !type.dimensions.empty? l = type.dimensions.first nested_sub = type.nested_sub if nested_sub.dynamic? raise DecodingError, "Wrong data size for static array" unless arg.size >= 32 * l offsets = (0...l).map do |i| off = Util.deserialize_big_endian_to_int arg[32 * i, 32] raise DecodingError, "Offset out of bounds" if off < 32 * l || off > arg.size - 32 off end offsets.each_with_index.map do |off, i| size = (i + 1 < offsets.length ? offsets[i + 1] : arg.size) - off type(nested_sub, arg[off, size]) end else # decoded static-size arrays with static sub-types (0...l).map { |i| type(nested_sub, arg[nested_sub.size * i, nested_sub.size]) } end else # decoded primitive types primitive_type type, arg end end |
Instance Method Details
#primitive_type(type, data) ⇒ String
Decodes primitive types.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/eth/abi/decoder.rb', line 129 def primitive_type(type, data) case type.base_type when "address" # decoded address with 0x-prefix Address.new(Util.bin_to_hex data[12..-1]).to_s.downcase when "string", "bytes" if type.sub_type.empty? size = Util.deserialize_big_endian_to_int data[0, 32] # decoded dynamic-sized array decoded = data[32..-1][0, size] decoded.force_encoding(Encoding::UTF_8) decoded else # decoded static-sized array data[0, type.sub_type.to_i] end when "hash" # decoded hash data[(32 - type.sub_type.to_i), type.sub_type.to_i] when "uint" # decoded unsigned integer Util.deserialize_big_endian_to_int data when "int" u = Util.deserialize_big_endian_to_int data i = u >= 2 ** (type.sub_type.to_i - 1) ? (u - 2 ** 256) : u # decoded integer i when "ureal", "ufixed" high, low = type.sub_type.split("x").map(&:to_i) # decoded unsigned fixed point numeric Util.deserialize_big_endian_to_int(data) * 1.0 / 2 ** low when "real", "fixed" high, low = type.sub_type.split("x").map(&:to_i) u = Util.deserialize_big_endian_to_int data i = u >= 2 ** (high + low - 1) ? (u - 2 ** (high + low)) : u # decoded fixed point numeric i * 1.0 / 2 ** low when "bool" # decoded boolean data[-1] == Constant::BYTE_ONE else raise DecodingError, "Unknown primitive type: #{type.base_type}" end end |
#type(type, arg) ⇒ String
Decodes a specific value, either static or dynamic.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/eth/abi/decoder.rb', line 33 def type(type, arg) if %w(string bytes).include?(type.base_type) and type.sub_type.empty? # Case: decoding a string/bytes if type.dimensions.empty? l = Util.deserialize_big_endian_to_int arg[0, 32] data = arg[32..-1] raise DecodingError, "Wrong data size for string/bytes object" unless data.size == Util.ceil32(l) # decoded strings and bytes data[0, l] # Case: decoding array of string/bytes else l = Util.deserialize_big_endian_to_int arg[0, 32] raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + 32 * l # Decode each element of the array (1..l).map do |i| pointer = Util.deserialize_big_endian_to_int arg[i * 32, 32] # Pointer to the size of the array's element raise DecodingError, "Offset out of bounds" if pointer < 32 * l || pointer > arg.size - 64 data_l = Util.deserialize_big_endian_to_int arg[32 + pointer, 32] # length of the element raise DecodingError, "Offset out of bounds" if pointer + 32 + Util.ceil32(data_l) > arg.size type(Type.parse(type.base_type), arg[pointer + 32, Util.ceil32(data_l) + 32]) end end elsif type.base_type == "tuple" && type.dimensions.empty? offset = 0 result = [] raise DecodingError, "Cannot decode tuples without known components" if type.components.nil? type.components.each_with_index do |c, i| if c.dynamic? pointer = Util.deserialize_big_endian_to_int arg[offset, 32] next_offset = if i + 1 < type.components.size Util.deserialize_big_endian_to_int arg[offset + 32, 32] else arg.size end raise DecodingError, "Offset out of bounds" if pointer > arg.size || next_offset > arg.size || next_offset < pointer result << type(c, arg[pointer, next_offset - pointer]) offset += 32 else size = c.size raise DecodingError, "Offset out of bounds" if offset + size > arg.size result << type(c, arg[offset, size]) offset += size end end result elsif type.dynamic? l = Util.deserialize_big_endian_to_int arg[0, 32] nested_sub = type.nested_sub if nested_sub.dynamic? raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + 32 * l offsets = (0...l).map do |i| off = Util.deserialize_big_endian_to_int arg[32 + 32 * i, 32] raise DecodingError, "Offset out of bounds" if off < 32 * l || off > arg.size - 64 off end offsets.map { |off| type(nested_sub, arg[32 + off..]) } else raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + nested_sub.size * l # decoded dynamic-sized arrays with static sub-types (0...l).map { |i| type(nested_sub, arg[32 + nested_sub.size * i, nested_sub.size]) } end elsif !type.dimensions.empty? l = type.dimensions.first nested_sub = type.nested_sub if nested_sub.dynamic? raise DecodingError, "Wrong data size for static array" unless arg.size >= 32 * l offsets = (0...l).map do |i| off = Util.deserialize_big_endian_to_int arg[32 * i, 32] raise DecodingError, "Offset out of bounds" if off < 32 * l || off > arg.size - 32 off end offsets.each_with_index.map do |off, i| size = (i + 1 < offsets.length ? offsets[i + 1] : arg.size) - off type(nested_sub, arg[off, size]) end else # decoded static-size arrays with static sub-types (0...l).map { |i| type(nested_sub, arg[nested_sub.size * i, nested_sub.size]) } end else # decoded primitive types primitive_type type, arg end end |