github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/accounts/abi/unpack.go (about) 1 package abi 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math/big" 7 "reflect" 8 9 "github.com/neatio-net/neatio/utilities/common" 10 ) 11 12 var ( 13 MaxUint256 = big.NewInt(0).Add( 14 big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil), 15 big.NewInt(-1)) 16 17 MaxInt256 = big.NewInt(0).Add( 18 big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil), 19 big.NewInt(-1)) 20 ) 21 22 func ReadInteger(typ byte, kind reflect.Kind, b []byte) interface{} { 23 switch kind { 24 case reflect.Uint8: 25 return b[len(b)-1] 26 case reflect.Uint16: 27 return binary.BigEndian.Uint16(b[len(b)-2:]) 28 case reflect.Uint32: 29 return binary.BigEndian.Uint32(b[len(b)-4:]) 30 case reflect.Uint64: 31 return binary.BigEndian.Uint64(b[len(b)-8:]) 32 case reflect.Int8: 33 return int8(b[len(b)-1]) 34 case reflect.Int16: 35 return int16(binary.BigEndian.Uint16(b[len(b)-2:])) 36 case reflect.Int32: 37 return int32(binary.BigEndian.Uint32(b[len(b)-4:])) 38 case reflect.Int64: 39 return int64(binary.BigEndian.Uint64(b[len(b)-8:])) 40 default: 41 42 ret := new(big.Int).SetBytes(b) 43 if typ == UintTy { 44 return ret 45 } 46 47 if ret.Cmp(MaxInt256) > 0 { 48 ret.Add(MaxUint256, big.NewInt(0).Neg(ret)) 49 ret.Add(ret, big.NewInt(1)) 50 ret.Neg(ret) 51 } 52 return ret 53 } 54 } 55 56 func readBool(word []byte) (bool, error) { 57 for _, b := range word[:31] { 58 if b != 0 { 59 return false, errBadBool 60 } 61 } 62 switch word[31] { 63 case 0: 64 return false, nil 65 case 1: 66 return true, nil 67 default: 68 return false, errBadBool 69 } 70 } 71 72 func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { 73 if t.T != FunctionTy { 74 return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array") 75 } 76 if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { 77 err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) 78 } else { 79 copy(funcTy[:], word[0:24]) 80 } 81 return 82 } 83 84 func ReadFixedBytes(t Type, word []byte) (interface{}, error) { 85 if t.T != FixedBytesTy { 86 return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") 87 } 88 89 array := reflect.New(t.Type).Elem() 90 91 reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) 92 return array.Interface(), nil 93 94 } 95 96 func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { 97 if size < 0 { 98 return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size) 99 } 100 if start+32*size > len(output) { 101 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) 102 } 103 104 var refSlice reflect.Value 105 106 if t.T == SliceTy { 107 108 refSlice = reflect.MakeSlice(t.Type, size, size) 109 } else if t.T == ArrayTy { 110 111 refSlice = reflect.New(t.Type).Elem() 112 } else { 113 return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") 114 } 115 116 elemSize := getTypeSize(*t.Elem) 117 118 for i, j := start, 0; j < size; i, j = i+elemSize, j+1 { 119 inter, err := toGoType(i, *t.Elem, output) 120 if err != nil { 121 return nil, err 122 } 123 124 refSlice.Index(j).Set(reflect.ValueOf(inter)) 125 } 126 127 return refSlice.Interface(), nil 128 } 129 130 func forTupleUnpack(t Type, output []byte) (interface{}, error) { 131 retval := reflect.New(t.Type).Elem() 132 virtualArgs := 0 133 for index, elem := range t.TupleElems { 134 marshalledValue, err := toGoType((index+virtualArgs)*32, *elem, output) 135 if elem.T == ArrayTy && !isDynamicType(*elem) { 136 137 virtualArgs += getTypeSize(*elem)/32 - 1 138 } else if elem.T == TupleTy && !isDynamicType(*elem) { 139 140 virtualArgs += getTypeSize(*elem)/32 - 1 141 } 142 if err != nil { 143 return nil, err 144 } 145 retval.Field(index).Set(reflect.ValueOf(marshalledValue)) 146 } 147 return retval.Interface(), nil 148 } 149 150 func toGoType(index int, t Type, output []byte) (interface{}, error) { 151 if index+32 > len(output) { 152 return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) 153 } 154 155 var ( 156 returnOutput []byte 157 begin, length int 158 err error 159 ) 160 161 if t.requiresLengthPrefix() { 162 begin, length, err = lengthPrefixPointsTo(index, output) 163 if err != nil { 164 return nil, err 165 } 166 } else { 167 returnOutput = output[index : index+32] 168 } 169 170 switch t.T { 171 case TupleTy: 172 if isDynamicType(t) { 173 begin, err := tuplePointsTo(index, output) 174 if err != nil { 175 return nil, err 176 } 177 return forTupleUnpack(t, output[begin:]) 178 } else { 179 return forTupleUnpack(t, output[index:]) 180 } 181 case SliceTy: 182 return forEachUnpack(t, output[begin:], 0, length) 183 case ArrayTy: 184 if isDynamicType(*t.Elem) { 185 offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:])) 186 return forEachUnpack(t, output[offset:], 0, t.Size) 187 } 188 return forEachUnpack(t, output[index:], 0, t.Size) 189 case StringTy: 190 return string(output[begin : begin+length]), nil 191 case IntTy, UintTy: 192 return ReadInteger(t.T, t.Kind, returnOutput), nil 193 case BoolTy: 194 return readBool(returnOutput) 195 case AddressTy: 196 return common.BytesToAddress(returnOutput), nil 197 case HashTy: 198 return common.BytesToHash(returnOutput), nil 199 case BytesTy: 200 return output[begin : begin+length], nil 201 case FixedBytesTy: 202 return ReadFixedBytes(t, returnOutput) 203 case FunctionTy: 204 return readFunctionType(t, returnOutput) 205 default: 206 return nil, fmt.Errorf("abi: unknown type %v", t.T) 207 } 208 } 209 210 func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { 211 bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32]) 212 bigOffsetEnd.Add(bigOffsetEnd, common.Big32) 213 outputLength := big.NewInt(int64(len(output))) 214 215 if bigOffsetEnd.Cmp(outputLength) > 0 { 216 return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength) 217 } 218 219 if bigOffsetEnd.BitLen() > 63 { 220 return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd) 221 } 222 223 offsetEnd := int(bigOffsetEnd.Uint64()) 224 lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd]) 225 226 totalSize := big.NewInt(0) 227 totalSize.Add(totalSize, bigOffsetEnd) 228 totalSize.Add(totalSize, lengthBig) 229 if totalSize.BitLen() > 63 { 230 return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize) 231 } 232 233 if totalSize.Cmp(outputLength) > 0 { 234 return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize) 235 } 236 start = int(bigOffsetEnd.Uint64()) 237 length = int(lengthBig.Uint64()) 238 return 239 } 240 241 func tuplePointsTo(index int, output []byte) (start int, err error) { 242 offset := big.NewInt(0).SetBytes(output[index : index+32]) 243 outputLen := big.NewInt(int64(len(output))) 244 245 if offset.Cmp(big.NewInt(int64(len(output)))) > 0 { 246 return 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", offset, outputLen) 247 } 248 if offset.BitLen() > 63 { 249 return 0, fmt.Errorf("abi offset larger than int64: %v", offset) 250 } 251 return int(offset.Uint64()), nil 252 }