github.com/tuotoo/go-ethereum@v1.7.4-0.20171121184211-049797d40a24/accounts/abi/unpack.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 "math/big" 23 "reflect" 24 25 "github.com/ethereum/go-ethereum/common" 26 ) 27 28 // unpacker is a utility interface that enables us to have 29 // abstraction between events and methods and also to properly 30 // "unpack" them; e.g. events use Inputs, methods use Outputs. 31 type unpacker interface { 32 tupleUnpack(v interface{}, output []byte) error 33 singleUnpack(v interface{}, output []byte) error 34 isTupleReturn() bool 35 } 36 37 // reads the integer based on its kind 38 func readInteger(kind reflect.Kind, b []byte) interface{} { 39 switch kind { 40 case reflect.Uint8: 41 return b[len(b)-1] 42 case reflect.Uint16: 43 return binary.BigEndian.Uint16(b[len(b)-2:]) 44 case reflect.Uint32: 45 return binary.BigEndian.Uint32(b[len(b)-4:]) 46 case reflect.Uint64: 47 return binary.BigEndian.Uint64(b[len(b)-8:]) 48 case reflect.Int8: 49 return int8(b[len(b)-1]) 50 case reflect.Int16: 51 return int16(binary.BigEndian.Uint16(b[len(b)-2:])) 52 case reflect.Int32: 53 return int32(binary.BigEndian.Uint32(b[len(b)-4:])) 54 case reflect.Int64: 55 return int64(binary.BigEndian.Uint64(b[len(b)-8:])) 56 default: 57 return new(big.Int).SetBytes(b) 58 } 59 } 60 61 // reads a bool 62 func readBool(word []byte) (bool, error) { 63 for _, b := range word[:31] { 64 if b != 0 { 65 return false, errBadBool 66 } 67 } 68 switch word[31] { 69 case 0: 70 return false, nil 71 case 1: 72 return true, nil 73 default: 74 return false, errBadBool 75 } 76 } 77 78 // A function type is simply the address with the function selection signature at the end. 79 // This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes) 80 func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { 81 if t.T != FunctionTy { 82 return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array.") 83 } 84 if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { 85 err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) 86 } else { 87 copy(funcTy[:], word[0:24]) 88 } 89 return 90 } 91 92 // through reflection, creates a fixed array to be read from 93 func readFixedBytes(t Type, word []byte) (interface{}, error) { 94 if t.T != FixedBytesTy { 95 return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array.") 96 } 97 // convert 98 array := reflect.New(t.Type).Elem() 99 100 reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) 101 return array.Interface(), nil 102 103 } 104 105 // iteratively unpack elements 106 func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { 107 if start+32*size > len(output) { 108 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) 109 } 110 111 // this value will become our slice or our array, depending on the type 112 var refSlice reflect.Value 113 slice := output[start : start+size*32] 114 115 if t.T == SliceTy { 116 // declare our slice 117 refSlice = reflect.MakeSlice(t.Type, size, size) 118 } else if t.T == ArrayTy { 119 // declare our array 120 refSlice = reflect.New(t.Type).Elem() 121 } else { 122 return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") 123 } 124 125 for i, j := start, 0; j*32 < len(slice); i, j = i+32, j+1 { 126 // this corrects the arrangement so that we get all the underlying array values 127 if t.Elem.T == ArrayTy && j != 0 { 128 i = start + t.Elem.Size*32*j 129 } 130 inter, err := toGoType(i, *t.Elem, output) 131 if err != nil { 132 return nil, err 133 } 134 // append the item to our reflect slice 135 refSlice.Index(j).Set(reflect.ValueOf(inter)) 136 } 137 138 // return the interface 139 return refSlice.Interface(), nil 140 } 141 142 // toGoType parses the output bytes and recursively assigns the value of these bytes 143 // into a go type with accordance with the ABI spec. 144 func toGoType(index int, t Type, output []byte) (interface{}, error) { 145 if index+32 > len(output) { 146 return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) 147 } 148 149 var ( 150 returnOutput []byte 151 begin, end int 152 err error 153 ) 154 155 // if we require a length prefix, find the beginning word and size returned. 156 if t.requiresLengthPrefix() { 157 begin, end, err = lengthPrefixPointsTo(index, output) 158 if err != nil { 159 return nil, err 160 } 161 } else { 162 returnOutput = output[index : index+32] 163 } 164 165 switch t.T { 166 case SliceTy: 167 return forEachUnpack(t, output, begin, end) 168 case ArrayTy: 169 return forEachUnpack(t, output, index, t.Size) 170 case StringTy: // variable arrays are written at the end of the return bytes 171 return string(output[begin : begin+end]), nil 172 case IntTy, UintTy: 173 return readInteger(t.Kind, returnOutput), nil 174 case BoolTy: 175 return readBool(returnOutput) 176 case AddressTy: 177 return common.BytesToAddress(returnOutput), nil 178 case HashTy: 179 return common.BytesToHash(returnOutput), nil 180 case BytesTy: 181 return output[begin : begin+end], nil 182 case FixedBytesTy: 183 return readFixedBytes(t, returnOutput) 184 case FunctionTy: 185 return readFunctionType(t, returnOutput) 186 default: 187 return nil, fmt.Errorf("abi: unknown type %v", t.T) 188 } 189 } 190 191 // interprets a 32 byte slice as an offset and then determines which indice to look to decode the type. 192 func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { 193 offset := int(binary.BigEndian.Uint64(output[index+24 : index+32])) 194 if offset+32 > len(output) { 195 return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) 196 } 197 length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32])) 198 if offset+32+length > len(output) { 199 return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length) 200 } 201 start = offset + 32 202 203 //fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start) 204 return 205 } 206 207 // checks for proper formatting of byte output 208 func bytesAreProper(output []byte) error { 209 if len(output) == 0 { 210 return fmt.Errorf("abi: unmarshalling empty output") 211 } else if len(output)%32 != 0 { 212 return fmt.Errorf("abi: improperly formatted output") 213 } else { 214 return nil 215 } 216 }