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  }