github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/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-wtc 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-wtc 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/wtc/go-wtc/common" 26 ) 27 28 // toGoSliceType parses the input and casts it to the proper slice defined by the ABI 29 // argument in T. 30 func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { 31 index := i * 32 32 // The slice must, at very least be large enough for the index+32 which is exactly the size required 33 // for the [offset in output, size of offset]. 34 if index+32 > len(output) { 35 return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32) 36 } 37 elem := t.Type.Elem 38 39 // first we need to create a slice of the type 40 var refSlice reflect.Value 41 switch elem.T { 42 case IntTy, UintTy, BoolTy: 43 // create a new reference slice matching the element type 44 switch t.Type.Kind { 45 case reflect.Bool: 46 refSlice = reflect.ValueOf([]bool(nil)) 47 case reflect.Uint8: 48 refSlice = reflect.ValueOf([]uint8(nil)) 49 case reflect.Uint16: 50 refSlice = reflect.ValueOf([]uint16(nil)) 51 case reflect.Uint32: 52 refSlice = reflect.ValueOf([]uint32(nil)) 53 case reflect.Uint64: 54 refSlice = reflect.ValueOf([]uint64(nil)) 55 case reflect.Int8: 56 refSlice = reflect.ValueOf([]int8(nil)) 57 case reflect.Int16: 58 refSlice = reflect.ValueOf([]int16(nil)) 59 case reflect.Int32: 60 refSlice = reflect.ValueOf([]int32(nil)) 61 case reflect.Int64: 62 refSlice = reflect.ValueOf([]int64(nil)) 63 default: 64 refSlice = reflect.ValueOf([]*big.Int(nil)) 65 } 66 case AddressTy: // address must be of slice Address 67 refSlice = reflect.ValueOf([]common.Address(nil)) 68 case HashTy: // hash must be of slice hash 69 refSlice = reflect.ValueOf([]common.Hash(nil)) 70 case FixedBytesTy: 71 refSlice = reflect.ValueOf([][]byte(nil)) 72 default: // no other types are supported 73 return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T) 74 } 75 76 var slice []byte 77 var size int 78 var offset int 79 if t.Type.IsSlice { 80 // get the offset which determines the start of this array ... 81 offset = int(binary.BigEndian.Uint64(output[index+24 : index+32])) 82 if offset+32 > len(output) { 83 return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) 84 } 85 86 slice = output[offset:] 87 // ... starting with the size of the array in elements ... 88 size = int(binary.BigEndian.Uint64(slice[24:32])) 89 slice = slice[32:] 90 // ... and make sure that we've at the very least the amount of bytes 91 // available in the buffer. 92 if size*32 > len(slice) { 93 return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32) 94 } 95 96 // reslice to match the required size 97 slice = slice[:size*32] 98 } else if t.Type.IsArray { 99 //get the number of elements in the array 100 size = t.Type.SliceSize 101 102 //check to make sure array size matches up 103 if index+32*size > len(output) { 104 return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size) 105 } 106 //slice is there for a fixed amount of times 107 slice = output[index : index+size*32] 108 } 109 110 for i := 0; i < size; i++ { 111 var ( 112 inter interface{} // interface type 113 returnOutput = slice[i*32 : i*32+32] // the return output 114 err error 115 ) 116 // set inter to the correct type (cast) 117 switch elem.T { 118 case IntTy, UintTy: 119 inter = readInteger(t.Type.Kind, returnOutput) 120 case BoolTy: 121 inter, err = readBool(returnOutput) 122 if err != nil { 123 return nil, err 124 } 125 case AddressTy: 126 inter = common.BytesToAddress(returnOutput) 127 case HashTy: 128 inter = common.BytesToHash(returnOutput) 129 case FixedBytesTy: 130 inter = returnOutput 131 } 132 // append the item to our reflect slice 133 refSlice = reflect.Append(refSlice, reflect.ValueOf(inter)) 134 } 135 136 // return the interface 137 return refSlice.Interface(), nil 138 } 139 140 func readInteger(kind reflect.Kind, b []byte) interface{} { 141 switch kind { 142 case reflect.Uint8: 143 return uint8(b[len(b)-1]) 144 case reflect.Uint16: 145 return binary.BigEndian.Uint16(b[len(b)-2:]) 146 case reflect.Uint32: 147 return binary.BigEndian.Uint32(b[len(b)-4:]) 148 case reflect.Uint64: 149 return binary.BigEndian.Uint64(b[len(b)-8:]) 150 case reflect.Int8: 151 return int8(b[len(b)-1]) 152 case reflect.Int16: 153 return int16(binary.BigEndian.Uint16(b[len(b)-2:])) 154 case reflect.Int32: 155 return int32(binary.BigEndian.Uint32(b[len(b)-4:])) 156 case reflect.Int64: 157 return int64(binary.BigEndian.Uint64(b[len(b)-8:])) 158 default: 159 return new(big.Int).SetBytes(b) 160 } 161 } 162 163 func readBool(word []byte) (bool, error) { 164 if len(word) != 32 { 165 return false, fmt.Errorf("abi: fatal error: incorrect word length") 166 } 167 168 for i, b := range word { 169 if b != 0 && i != 31 { 170 return false, errBadBool 171 } 172 } 173 switch word[31] { 174 case 0: 175 return false, nil 176 case 1: 177 return true, nil 178 default: 179 return false, errBadBool 180 } 181 182 } 183 184 // toGoType parses the input and casts it to the proper type defined by the ABI 185 // argument in T. 186 func toGoType(i int, t Argument, output []byte) (interface{}, error) { 187 // we need to treat slices differently 188 if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy { 189 return toGoSlice(i, t, output) 190 } 191 192 index := i * 32 193 if index+32 > len(output) { 194 return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) 195 } 196 197 // Parse the given index output and check whether we need to read 198 // a different offset and length based on the type (i.e. string, bytes) 199 var returnOutput []byte 200 switch t.Type.T { 201 case StringTy, BytesTy: // variable arrays are written at the end of the return bytes 202 // parse offset from which we should start reading 203 offset := int(binary.BigEndian.Uint64(output[index+24 : index+32])) 204 if offset+32 > len(output) { 205 return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32) 206 } 207 // parse the size up until we should be reading 208 size := int(binary.BigEndian.Uint64(output[offset+24 : offset+32])) 209 if offset+32+size > len(output) { 210 return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size) 211 } 212 213 // get the bytes for this return value 214 returnOutput = output[offset+32 : offset+32+size] 215 default: 216 returnOutput = output[index : index+32] 217 } 218 219 // convert the bytes to whatever is specified by the ABI. 220 switch t.Type.T { 221 case IntTy, UintTy: 222 return readInteger(t.Type.Kind, returnOutput), nil 223 case BoolTy: 224 return readBool(returnOutput) 225 case AddressTy: 226 return common.BytesToAddress(returnOutput), nil 227 case HashTy: 228 return common.BytesToHash(returnOutput), nil 229 case BytesTy, FixedBytesTy, FunctionTy: 230 return returnOutput, nil 231 case StringTy: 232 return string(returnOutput), nil 233 } 234 return nil, fmt.Errorf("abi: unknown type %v", t.Type.T) 235 }