github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/evm/abi/packing.go (about) 1 package abi 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 8 "github.com/hyperledger/burrow/binary" 9 ) 10 11 func Pack(argSpec []Argument, args ...interface{}) ([]byte, error) { 12 getArg, err := argGetter(argSpec, args, false) 13 if err != nil { 14 return nil, err 15 } 16 return pack(argSpec, getArg) 17 } 18 19 func Unpack(argSpec []Argument, data []byte, args ...interface{}) error { 20 getArg, err := argGetter(argSpec, args, true) 21 if err != nil { 22 return err 23 } 24 return unpack(argSpec, data, getArg) 25 } 26 27 func PackEvent(eventSpec *EventSpec, args ...interface{}) ([]binary.Word256, []byte, error) { 28 getArg, err := argGetter(eventSpec.Inputs, args, false) 29 if err != nil { 30 return nil, nil, err 31 } 32 data, err := pack(eventSpec.Inputs, getArg) 33 if err != nil { 34 return nil, nil, err 35 } 36 topics, err := packTopics(eventSpec, getArg) 37 return topics, data, err 38 } 39 40 func UnpackEvent(eventSpec *EventSpec, topics []binary.Word256, data []byte, args ...interface{}) error { 41 getArg, err := argGetter(eventSpec.Inputs, args, true) 42 if err != nil { 43 return err 44 } 45 err = unpack(eventSpec.Inputs, data, getArg) 46 if err != nil { 47 return err 48 } 49 return unpackTopics(eventSpec, topics, getArg) 50 } 51 52 // UnpackRevert decodes the revert reason if a contract called revert. If no 53 // reason was given, message will be nil else it will point to the string 54 func UnpackRevert(data []byte) (message *string, err error) { 55 if len(data) > 0 { 56 var msg string 57 err = revertAbi.UnpackWithID(data, &msg) 58 message = &msg 59 } 60 return 61 } 62 63 // revertAbi exists to decode reverts. Any contract function call fail using revert(), assert() or require(). 64 // If a function exits this way, the this hardcoded ABI will be used. 65 var revertAbi *Spec 66 67 func init() { 68 var err error 69 revertAbi, err = ReadSpec([]byte(`[{"name":"Error","type":"function","outputs":[{"type":"string"}],"inputs":[{"type":"string"}]}]`)) 70 if err != nil { 71 panic(fmt.Sprintf("internal error: failed to build revert abi: %v", err)) 72 } 73 } 74 75 func argGetter(argSpec []Argument, args []interface{}, ptr bool) (func(int) interface{}, error) { 76 if len(args) == 1 { 77 rv := reflect.ValueOf(args[0]) 78 if rv.Kind() == reflect.Ptr { 79 rv = rv.Elem() 80 } else if ptr { 81 return nil, fmt.Errorf("struct pointer required in order to set values, but got %v", rv.Kind()) 82 } 83 if rv.Kind() != reflect.Struct { 84 if len(args) == 1 { 85 // Treat s single arg 86 return func(i int) interface{} { return args[i] }, nil 87 } 88 return nil, fmt.Errorf("expected single argument to be struct but got %v", rv.Kind()) 89 } 90 fields := rv.NumField() 91 if fields != len(argSpec) { 92 return nil, fmt.Errorf("%d arguments in struct expected, %d received", len(argSpec), fields) 93 } 94 if ptr { 95 return func(i int) interface{} { 96 return rv.Field(i).Addr().Interface() 97 }, nil 98 } 99 return func(i int) interface{} { 100 return rv.Field(i).Interface() 101 }, nil 102 } 103 if len(args) == len(argSpec) { 104 return func(i int) interface{} { 105 return args[i] 106 }, nil 107 } 108 return nil, fmt.Errorf("%d arguments expected, %d received", len(argSpec), len(args)) 109 } 110 111 func packTopics(eventSpec *EventSpec, getArg func(int) interface{}) ([]binary.Word256, error) { 112 topics := make([]binary.Word256, 0, 5) 113 if !eventSpec.Anonymous { 114 topics = append(topics, binary.Word256(eventSpec.ID)) 115 } 116 for i, a := range eventSpec.Inputs { 117 if a.Indexed { 118 data, err := a.EVM.pack(getArg(i)) 119 if err != nil { 120 return nil, err 121 } 122 var topic binary.Word256 123 copy(topic[:], data) 124 topics = append(topics, topic) 125 } 126 } 127 return topics, nil 128 } 129 130 // Unpack event topics 131 func unpackTopics(eventSpec *EventSpec, topics []binary.Word256, getArg func(int) interface{}) error { 132 // First unpack the topic fields 133 topicIndex := 0 134 if !eventSpec.Anonymous { 135 topicIndex++ 136 } 137 138 for i, a := range eventSpec.Inputs { 139 if a.Indexed { 140 _, err := a.EVM.unpack(topics[topicIndex][:], 0, getArg(i)) 141 if err != nil { 142 return err 143 } 144 topicIndex++ 145 } 146 } 147 return nil 148 } 149 150 func pack(argSpec []Argument, getArg func(int) interface{}) ([]byte, error) { 151 packed := make([]byte, 0) 152 var packedDynamic []byte 153 fixedSize := 0 154 // Anything dynamic is stored after the "fixed" block. For the dynamic types, the fixed 155 // block contains byte offsets to the data. We need to know the length of the fixed 156 // block, so we can calcute the offsets 157 for _, as := range argSpec { 158 if as.Indexed { 159 continue 160 } 161 if as.IsArray { 162 if as.ArrayLength > 0 { 163 fixedSize += ElementSize * int(as.ArrayLength) 164 } else { 165 fixedSize += ElementSize 166 } 167 } else { 168 fixedSize += ElementSize 169 } 170 } 171 172 addArg := func(v interface{}, a Argument) error { 173 var b []byte 174 var err error 175 if a.EVM.Dynamic() { 176 offset := EVMUint{M: 256} 177 b, _ = offset.pack(fixedSize) 178 d, err := a.EVM.pack(v) 179 if err != nil { 180 return err 181 } 182 fixedSize += len(d) 183 packedDynamic = append(packedDynamic, d...) 184 } else { 185 b, err = a.EVM.pack(v) 186 if err != nil { 187 return err 188 } 189 } 190 packed = append(packed, b...) 191 return nil 192 } 193 194 for i, as := range argSpec { 195 if as.Indexed { 196 continue 197 } 198 a := getArg(i) 199 if as.IsArray { 200 s, ok := a.(string) 201 if ok && s[0:1] == "[" && s[len(s)-1:] == "]" { 202 a = strings.Split(s[1:len(s)-1], ",") 203 } 204 205 val := reflect.ValueOf(a) 206 if val.Kind() != reflect.Slice && val.Kind() != reflect.Array { 207 return nil, fmt.Errorf("argument %d should be array or slice, not %s", i, val.Kind().String()) 208 } 209 210 if as.ArrayLength > 0 { 211 if as.ArrayLength != uint64(val.Len()) { 212 return nil, fmt.Errorf("argumment %d should be array of %d, not %d", i, as.ArrayLength, val.Len()) 213 } 214 215 for n := 0; n < val.Len(); n++ { 216 err := addArg(val.Index(n).Interface(), as) 217 if err != nil { 218 return nil, err 219 } 220 } 221 } else { 222 // dynamic array 223 offset := EVMUint{M: 256} 224 b, _ := offset.pack(fixedSize) 225 packed = append(packed, b...) 226 fixedSize += len(b) 227 228 // store length 229 b, _ = offset.pack(val.Len()) 230 packedDynamic = append(packedDynamic, b...) 231 for n := 0; n < val.Len(); n++ { 232 d, err := as.EVM.pack(val.Index(n).Interface()) 233 if err != nil { 234 return nil, err 235 } 236 fixedSize += len(d) 237 packedDynamic = append(packedDynamic, d...) 238 } 239 } 240 } else { 241 err := addArg(a, as) 242 if err != nil { 243 return nil, err 244 } 245 } 246 } 247 248 return append(packed, packedDynamic...), nil 249 } 250 251 func unpack(argSpec []Argument, data []byte, getArg func(int) interface{}) error { 252 offset := 0 253 offType := EVMInt{M: 64} 254 255 getPrimitive := func(e interface{}, a Argument) error { 256 if a.EVM.Dynamic() { 257 var o int64 258 l, err := offType.unpack(data, offset, &o) 259 if err != nil { 260 return err 261 } 262 offset += l 263 _, err = a.EVM.unpack(data, int(o), e) 264 if err != nil { 265 return err 266 } 267 } else { 268 l, err := a.EVM.unpack(data, offset, e) 269 if err != nil { 270 return err 271 } 272 offset += l 273 } 274 275 return nil 276 } 277 278 for i, as := range argSpec { 279 if as.Indexed { 280 continue 281 } 282 283 arg := getArg(i) 284 if as.IsArray { 285 var array *[]interface{} 286 287 array, ok := arg.(*[]interface{}) 288 if !ok { 289 if _, ok := arg.(*string); ok { 290 // We have been asked to return the value as a string; make intermediate 291 // array of strings; we will concatenate after 292 intermediate := make([]interface{}, as.ArrayLength) 293 for i := range intermediate { 294 intermediate[i] = new(string) 295 } 296 array = &intermediate 297 } else { 298 return fmt.Errorf("argument %d should be array, slice or string", i) 299 } 300 } 301 302 if as.ArrayLength > 0 { 303 if int(as.ArrayLength) != len(*array) { 304 return fmt.Errorf("argument %d should be array or slice of %d elements", i, as.ArrayLength) 305 } 306 307 for n := 0; n < len(*array); n++ { 308 err := getPrimitive((*array)[n], as) 309 if err != nil { 310 return err 311 } 312 } 313 } else { 314 var o int64 315 var length int64 316 317 l, err := offType.unpack(data, offset, &o) 318 if err != nil { 319 return err 320 } 321 322 offset += l 323 s, err := offType.unpack(data, int(o), &length) 324 if err != nil { 325 return err 326 } 327 o += int64(s) 328 329 intermediate := make([]interface{}, length) 330 331 if _, ok := arg.(*string); ok { 332 // We have been asked to return the value as a string; make intermediate 333 // array of strings; we will concatenate after 334 for i := range intermediate { 335 intermediate[i] = new(string) 336 } 337 } else { 338 for i := range intermediate { 339 intermediate[i] = as.EVM.getGoType() 340 } 341 } 342 343 for i := 0; i < int(length); i++ { 344 l, err = as.EVM.unpack(data, int(o), intermediate[i]) 345 if err != nil { 346 return err 347 } 348 o += int64(l) 349 } 350 351 array = &intermediate 352 } 353 354 // If we were supposed to return a string, convert it back 355 if ret, ok := arg.(*string); ok { 356 s := "[" 357 for i, e := range *array { 358 if i > 0 { 359 s += "," 360 } 361 s += *(e.(*string)) 362 } 363 s += "]" 364 *ret = s 365 } 366 } else { 367 err := getPrimitive(arg, as) 368 if err != nil { 369 return err 370 } 371 } 372 } 373 374 return nil 375 }