github.com/iotexproject/iotex-core@v1.14.1-rc1/tools/executiontester/blockchain/slice_assembler.go (about) 1 package blockchain 2 3 import ( 4 "reflect" 5 6 "github.com/iotexproject/go-pkgs/hash" 7 ) 8 9 type ( 10 // ICanBytes is []byte 11 ICanBytes interface { 12 Bytes() []byte 13 } 14 15 // SliceAssembler is an interface to pack arguments for ABI 16 SliceAssembler interface { 17 PackArguments(args ...interface{}) ([]byte, error) 18 IsDynamicType(param interface{}) bool 19 } 20 21 sliceAssembler struct { 22 } 23 ) 24 25 // NewSliceAssembler creates a slice assembler 26 func NewSliceAssembler() SliceAssembler { 27 return &sliceAssembler{} 28 } 29 30 func (sa *sliceAssembler) IsDynamicType(param interface{}) bool { 31 t := reflect.TypeOf(param) 32 33 if t.Kind() == reflect.String { 34 return true 35 } 36 37 if t.Kind() != reflect.Slice { 38 return false 39 } 40 41 if t.Elem().Kind() == reflect.Uint8 && reflect.ValueOf(param).Len() <= 32 { 42 return false 43 } 44 return true 45 } 46 47 func (sa *sliceAssembler) PackArguments(args ...interface{}) ([]byte, error) { 48 var variableInput []byte 49 var ret []byte 50 inputOffset := len(args) * 32 51 52 for _, a := range args { 53 packed := sa.pack(a) 54 55 if !sa.IsDynamicType(a) { 56 ret = append(ret, packed...) 57 continue 58 } 59 60 ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) 61 inputOffset += len(packed) 62 variableInput = append(variableInput, packed...) 63 } 64 65 ret = append(ret, variableInput...) 66 return ret, nil 67 } 68 69 func (sa *sliceAssembler) pack(a interface{}) []byte { 70 switch a.(type) { 71 case string: 72 bs, _ := packByte([]byte(a.(string))) 73 return bs 74 75 case []byte: 76 if len(a.([]byte)) > 32 { 77 bs, _ := packByte(a.([]byte)) 78 return bs 79 } 80 } 81 82 if !sa.IsDynamicType(a) { 83 switch a.(type) { 84 case []byte: 85 bs := rightPadBytes(a.([]byte), 32) 86 return bs[:] 87 case bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 88 return packNum(reflect.ValueOf(a)) 89 case ICanBytes: 90 bs := hash.BytesToHash256(a.(ICanBytes).Bytes()) 91 return bs[:] 92 default: 93 panic("fail") 94 } 95 } 96 97 v := reflect.ValueOf(a) 98 ret := packNum(reflect.ValueOf(v.Len())) 99 for i := 0; i < v.Len(); i++ { 100 switch v.Index(i).Interface().(type) { 101 case ICanBytes: 102 item := v.Index(i) 103 if !item.IsValid() { 104 item = item.Elem() 105 } 106 bs := hash.BytesToHash256(item.Interface().(ICanBytes).Bytes()) 107 ret = append(ret, bs[:]...) 108 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 109 ret = append(ret, packNum(reflect.ValueOf(v.Index(i).Interface()))...) 110 default: 111 panic("abi: fatal error") 112 } 113 } 114 return ret 115 }