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  }