github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/accounts/abi/unpack.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-wtc library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-wtc library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package abi
    18  
    19  import (
    20  	"encoding/binary"
    21  	"fmt"
    22  	"math/big"
    23  	"reflect"
    24  
    25  	"github.com/wtc/go-wtc/common"
    26  )
    27  
    28  // toGoSliceType parses the input and casts it to the proper slice defined by the ABI
    29  // argument in T.
    30  func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
    31  	index := i * 32
    32  	// The slice must, at very least be large enough for the index+32 which is exactly the size required
    33  	// for the [offset in output, size of offset].
    34  	if index+32 > len(output) {
    35  		return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32)
    36  	}
    37  	elem := t.Type.Elem
    38  
    39  	// first we need to create a slice of the type
    40  	var refSlice reflect.Value
    41  	switch elem.T {
    42  	case IntTy, UintTy, BoolTy:
    43  		// create a new reference slice matching the element type
    44  		switch t.Type.Kind {
    45  		case reflect.Bool:
    46  			refSlice = reflect.ValueOf([]bool(nil))
    47  		case reflect.Uint8:
    48  			refSlice = reflect.ValueOf([]uint8(nil))
    49  		case reflect.Uint16:
    50  			refSlice = reflect.ValueOf([]uint16(nil))
    51  		case reflect.Uint32:
    52  			refSlice = reflect.ValueOf([]uint32(nil))
    53  		case reflect.Uint64:
    54  			refSlice = reflect.ValueOf([]uint64(nil))
    55  		case reflect.Int8:
    56  			refSlice = reflect.ValueOf([]int8(nil))
    57  		case reflect.Int16:
    58  			refSlice = reflect.ValueOf([]int16(nil))
    59  		case reflect.Int32:
    60  			refSlice = reflect.ValueOf([]int32(nil))
    61  		case reflect.Int64:
    62  			refSlice = reflect.ValueOf([]int64(nil))
    63  		default:
    64  			refSlice = reflect.ValueOf([]*big.Int(nil))
    65  		}
    66  	case AddressTy: // address must be of slice Address
    67  		refSlice = reflect.ValueOf([]common.Address(nil))
    68  	case HashTy: // hash must be of slice hash
    69  		refSlice = reflect.ValueOf([]common.Hash(nil))
    70  	case FixedBytesTy:
    71  		refSlice = reflect.ValueOf([][]byte(nil))
    72  	default: // no other types are supported
    73  		return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
    74  	}
    75  
    76  	var slice []byte
    77  	var size int
    78  	var offset int
    79  	if t.Type.IsSlice {
    80  		// get the offset which determines the start of this array ...
    81  		offset = int(binary.BigEndian.Uint64(output[index+24 : index+32]))
    82  		if offset+32 > len(output) {
    83  			return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
    84  		}
    85  
    86  		slice = output[offset:]
    87  		// ... starting with the size of the array in elements ...
    88  		size = int(binary.BigEndian.Uint64(slice[24:32]))
    89  		slice = slice[32:]
    90  		// ... and make sure that we've at the very least the amount of bytes
    91  		// available in the buffer.
    92  		if size*32 > len(slice) {
    93  			return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32)
    94  		}
    95  
    96  		// reslice to match the required size
    97  		slice = slice[:size*32]
    98  	} else if t.Type.IsArray {
    99  		//get the number of elements in the array
   100  		size = t.Type.SliceSize
   101  
   102  		//check to make sure array size matches up
   103  		if index+32*size > len(output) {
   104  			return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size)
   105  		}
   106  		//slice is there for a fixed amount of times
   107  		slice = output[index : index+size*32]
   108  	}
   109  
   110  	for i := 0; i < size; i++ {
   111  		var (
   112  			inter        interface{}             // interface type
   113  			returnOutput = slice[i*32 : i*32+32] // the return output
   114  			err          error
   115  		)
   116  		// set inter to the correct type (cast)
   117  		switch elem.T {
   118  		case IntTy, UintTy:
   119  			inter = readInteger(t.Type.Kind, returnOutput)
   120  		case BoolTy:
   121  			inter, err = readBool(returnOutput)
   122  			if err != nil {
   123  				return nil, err
   124  			}
   125  		case AddressTy:
   126  			inter = common.BytesToAddress(returnOutput)
   127  		case HashTy:
   128  			inter = common.BytesToHash(returnOutput)
   129  		case FixedBytesTy:
   130  			inter = returnOutput
   131  		}
   132  		// append the item to our reflect slice
   133  		refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
   134  	}
   135  
   136  	// return the interface
   137  	return refSlice.Interface(), nil
   138  }
   139  
   140  func readInteger(kind reflect.Kind, b []byte) interface{} {
   141  	switch kind {
   142  	case reflect.Uint8:
   143  		return uint8(b[len(b)-1])
   144  	case reflect.Uint16:
   145  		return binary.BigEndian.Uint16(b[len(b)-2:])
   146  	case reflect.Uint32:
   147  		return binary.BigEndian.Uint32(b[len(b)-4:])
   148  	case reflect.Uint64:
   149  		return binary.BigEndian.Uint64(b[len(b)-8:])
   150  	case reflect.Int8:
   151  		return int8(b[len(b)-1])
   152  	case reflect.Int16:
   153  		return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
   154  	case reflect.Int32:
   155  		return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
   156  	case reflect.Int64:
   157  		return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
   158  	default:
   159  		return new(big.Int).SetBytes(b)
   160  	}
   161  }
   162  
   163  func readBool(word []byte) (bool, error) {
   164  	if len(word) != 32 {
   165  		return false, fmt.Errorf("abi: fatal error: incorrect word length")
   166  	}
   167  
   168  	for i, b := range word {
   169  		if b != 0 && i != 31 {
   170  			return false, errBadBool
   171  		}
   172  	}
   173  	switch word[31] {
   174  	case 0:
   175  		return false, nil
   176  	case 1:
   177  		return true, nil
   178  	default:
   179  		return false, errBadBool
   180  	}
   181  
   182  }
   183  
   184  // toGoType parses the input and casts it to the proper type defined by the ABI
   185  // argument in T.
   186  func toGoType(i int, t Argument, output []byte) (interface{}, error) {
   187  	// we need to treat slices differently
   188  	if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy {
   189  		return toGoSlice(i, t, output)
   190  	}
   191  
   192  	index := i * 32
   193  	if index+32 > len(output) {
   194  		return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
   195  	}
   196  
   197  	// Parse the given index output and check whether we need to read
   198  	// a different offset and length based on the type (i.e. string, bytes)
   199  	var returnOutput []byte
   200  	switch t.Type.T {
   201  	case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
   202  		// parse offset from which we should start reading
   203  		offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
   204  		if offset+32 > len(output) {
   205  			return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
   206  		}
   207  		// parse the size up until we should be reading
   208  		size := int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
   209  		if offset+32+size > len(output) {
   210  			return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
   211  		}
   212  
   213  		// get the bytes for this return value
   214  		returnOutput = output[offset+32 : offset+32+size]
   215  	default:
   216  		returnOutput = output[index : index+32]
   217  	}
   218  
   219  	// convert the bytes to whatever is specified by the ABI.
   220  	switch t.Type.T {
   221  	case IntTy, UintTy:
   222  		return readInteger(t.Type.Kind, returnOutput), nil
   223  	case BoolTy:
   224  		return readBool(returnOutput)
   225  	case AddressTy:
   226  		return common.BytesToAddress(returnOutput), nil
   227  	case HashTy:
   228  		return common.BytesToHash(returnOutput), nil
   229  	case BytesTy, FixedBytesTy, FunctionTy:
   230  		return returnOutput, nil
   231  	case StringTy:
   232  		return string(returnOutput), nil
   233  	}
   234  	return nil, fmt.Errorf("abi: unknown type %v", t.Type.T)
   235  }