github.com/MetalBlockchain/subnet-evm@v0.4.9/accounts/abi/unpack.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2017 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package abi 28 29 import ( 30 "encoding/binary" 31 "fmt" 32 "math/big" 33 "reflect" 34 35 "github.com/ethereum/go-ethereum/common" 36 ) 37 38 var ( 39 // MaxUint256 is the maximum value that can be represented by a uint256. 40 MaxUint256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1) 41 // MaxInt256 is the maximum value that can be represented by a int256. 42 MaxInt256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 255), common.Big1) 43 ) 44 45 // ReadInteger reads the integer based on its kind and returns the appropriate value. 46 func ReadInteger(typ Type, b []byte) interface{} { 47 if typ.T == UintTy { 48 switch typ.Size { 49 case 8: 50 return b[len(b)-1] 51 case 16: 52 return binary.BigEndian.Uint16(b[len(b)-2:]) 53 case 32: 54 return binary.BigEndian.Uint32(b[len(b)-4:]) 55 case 64: 56 return binary.BigEndian.Uint64(b[len(b)-8:]) 57 default: 58 // the only case left for unsigned integer is uint256. 59 return new(big.Int).SetBytes(b) 60 } 61 } 62 switch typ.Size { 63 case 8: 64 return int8(b[len(b)-1]) 65 case 16: 66 return int16(binary.BigEndian.Uint16(b[len(b)-2:])) 67 case 32: 68 return int32(binary.BigEndian.Uint32(b[len(b)-4:])) 69 case 64: 70 return int64(binary.BigEndian.Uint64(b[len(b)-8:])) 71 default: 72 // the only case left for integer is int256 73 // big.SetBytes can't tell if a number is negative or positive in itself. 74 // On EVM, if the returned number > max int256, it is negative. 75 // A number is > max int256 if the bit at position 255 is set. 76 ret := new(big.Int).SetBytes(b) 77 if ret.Bit(255) == 1 { 78 ret.Add(MaxUint256, new(big.Int).Neg(ret)) 79 ret.Add(ret, common.Big1) 80 ret.Neg(ret) 81 } 82 return ret 83 } 84 } 85 86 // readBool reads a bool. 87 func readBool(word []byte) (bool, error) { 88 for _, b := range word[:31] { 89 if b != 0 { 90 return false, errBadBool 91 } 92 } 93 switch word[31] { 94 case 0: 95 return false, nil 96 case 1: 97 return true, nil 98 default: 99 return false, errBadBool 100 } 101 } 102 103 // A function type is simply the address with the function selection signature at the end. 104 // 105 // readFunctionType enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes) 106 func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { 107 if t.T != FunctionTy { 108 return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array") 109 } 110 if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { 111 err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) 112 } else { 113 copy(funcTy[:], word[0:24]) 114 } 115 return 116 } 117 118 // ReadFixedBytes uses reflection to create a fixed array to be read from. 119 func ReadFixedBytes(t Type, word []byte) (interface{}, error) { 120 if t.T != FixedBytesTy { 121 return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") 122 } 123 // convert 124 array := reflect.New(t.GetType()).Elem() 125 126 reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) 127 return array.Interface(), nil 128 } 129 130 // forEachUnpack iteratively unpack elements. 131 func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { 132 if size < 0 { 133 return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size) 134 } 135 if start+32*size > len(output) { 136 return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) 137 } 138 139 // this value will become our slice or our array, depending on the type 140 var refSlice reflect.Value 141 142 if t.T == SliceTy { 143 // declare our slice 144 refSlice = reflect.MakeSlice(t.GetType(), size, size) 145 } else if t.T == ArrayTy { 146 // declare our array 147 refSlice = reflect.New(t.GetType()).Elem() 148 } else { 149 return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") 150 } 151 152 // Arrays have packed elements, resulting in longer unpack steps. 153 // Slices have just 32 bytes per element (pointing to the contents). 154 elemSize := getTypeSize(*t.Elem) 155 156 for i, j := start, 0; j < size; i, j = i+elemSize, j+1 { 157 inter, err := toGoType(i, *t.Elem, output) 158 if err != nil { 159 return nil, err 160 } 161 162 // append the item to our reflect slice 163 refSlice.Index(j).Set(reflect.ValueOf(inter)) 164 } 165 166 // return the interface 167 return refSlice.Interface(), nil 168 } 169 170 func forTupleUnpack(t Type, output []byte) (interface{}, error) { 171 retval := reflect.New(t.GetType()).Elem() 172 virtualArgs := 0 173 for index, elem := range t.TupleElems { 174 marshalledValue, err := toGoType((index+virtualArgs)*32, *elem, output) 175 if err != nil { 176 return nil, err 177 } 178 if elem.T == ArrayTy && !isDynamicType(*elem) { 179 // If we have a static array, like [3]uint256, these are coded as 180 // just like uint256,uint256,uint256. 181 // This means that we need to add two 'virtual' arguments when 182 // we count the index from now on. 183 // 184 // Array values nested multiple levels deep are also encoded inline: 185 // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256 186 // 187 // Calculate the full array size to get the correct offset for the next argument. 188 // Decrement it by 1, as the normal index increment is still applied. 189 virtualArgs += getTypeSize(*elem)/32 - 1 190 } else if elem.T == TupleTy && !isDynamicType(*elem) { 191 // If we have a static tuple, like (uint256, bool, uint256), these are 192 // coded as just like uint256,bool,uint256 193 virtualArgs += getTypeSize(*elem)/32 - 1 194 } 195 retval.Field(index).Set(reflect.ValueOf(marshalledValue)) 196 } 197 return retval.Interface(), nil 198 } 199 200 // toGoType parses the output bytes and recursively assigns the value of these bytes 201 // into a go type with accordance with the ABI spec. 202 func toGoType(index int, t Type, output []byte) (interface{}, error) { 203 if index+32 > len(output) { 204 return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) 205 } 206 207 var ( 208 returnOutput []byte 209 begin, length int 210 err error 211 ) 212 213 // if we require a length prefix, find the beginning word and size returned. 214 if t.requiresLengthPrefix() { 215 begin, length, err = lengthPrefixPointsTo(index, output) 216 if err != nil { 217 return nil, err 218 } 219 } else { 220 returnOutput = output[index : index+32] 221 } 222 223 switch t.T { 224 case TupleTy: 225 if isDynamicType(t) { 226 begin, err := tuplePointsTo(index, output) 227 if err != nil { 228 return nil, err 229 } 230 return forTupleUnpack(t, output[begin:]) 231 } 232 return forTupleUnpack(t, output[index:]) 233 case SliceTy: 234 return forEachUnpack(t, output[begin:], 0, length) 235 case ArrayTy: 236 if isDynamicType(*t.Elem) { 237 offset := binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:]) 238 if offset > uint64(len(output)) { 239 return nil, fmt.Errorf("abi: toGoType offset greater than output length: offset: %d, len(output): %d", offset, len(output)) 240 } 241 return forEachUnpack(t, output[offset:], 0, t.Size) 242 } 243 return forEachUnpack(t, output[index:], 0, t.Size) 244 case StringTy: // variable arrays are written at the end of the return bytes 245 return string(output[begin : begin+length]), nil 246 case IntTy, UintTy: 247 return ReadInteger(t, returnOutput), nil 248 case BoolTy: 249 return readBool(returnOutput) 250 case AddressTy: 251 return common.BytesToAddress(returnOutput), nil 252 case HashTy: 253 return common.BytesToHash(returnOutput), nil 254 case BytesTy: 255 return output[begin : begin+length], nil 256 case FixedBytesTy: 257 return ReadFixedBytes(t, returnOutput) 258 case FunctionTy: 259 return readFunctionType(t, returnOutput) 260 default: 261 return nil, fmt.Errorf("abi: unknown type %v", t.T) 262 } 263 } 264 265 // lengthPrefixPointsTo interprets a 32 byte slice as an offset and then determines which indices to look to decode the type. 266 func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { 267 bigOffsetEnd := new(big.Int).SetBytes(output[index : index+32]) 268 bigOffsetEnd.Add(bigOffsetEnd, common.Big32) 269 outputLength := big.NewInt(int64(len(output))) 270 271 if bigOffsetEnd.Cmp(outputLength) > 0 { 272 return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength) 273 } 274 275 if bigOffsetEnd.BitLen() > 63 { 276 return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd) 277 } 278 279 offsetEnd := int(bigOffsetEnd.Uint64()) 280 lengthBig := new(big.Int).SetBytes(output[offsetEnd-32 : offsetEnd]) 281 282 totalSize := new(big.Int).Add(bigOffsetEnd, lengthBig) 283 if totalSize.BitLen() > 63 { 284 return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize) 285 } 286 287 if totalSize.Cmp(outputLength) > 0 { 288 return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize) 289 } 290 start = int(bigOffsetEnd.Uint64()) 291 length = int(lengthBig.Uint64()) 292 return 293 } 294 295 // tuplePointsTo resolves the location reference for dynamic tuple. 296 func tuplePointsTo(index int, output []byte) (start int, err error) { 297 offset := new(big.Int).SetBytes(output[index : index+32]) 298 outputLen := big.NewInt(int64(len(output))) 299 300 if offset.Cmp(outputLen) > 0 { 301 return 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", offset, outputLen) 302 } 303 if offset.BitLen() > 63 { 304 return 0, fmt.Errorf("abi offset larger than int64: %v", offset) 305 } 306 return int(offset.Uint64()), nil 307 }