github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/accounts/abi/unpack.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:26</date>
    10  //</624342584155705344>
    11  
    12  
    13  package abi
    14  
    15  import (
    16  	"encoding/binary"
    17  	"fmt"
    18  	"math/big"
    19  	"reflect"
    20  
    21  	"github.com/ethereum/go-ethereum/common"
    22  )
    23  
    24  //根据整数的类型读取整数
    25  func readInteger(kind reflect.Kind, b []byte) interface{} {
    26  	switch kind {
    27  	case reflect.Uint8:
    28  		return b[len(b)-1]
    29  	case reflect.Uint16:
    30  		return binary.BigEndian.Uint16(b[len(b)-2:])
    31  	case reflect.Uint32:
    32  		return binary.BigEndian.Uint32(b[len(b)-4:])
    33  	case reflect.Uint64:
    34  		return binary.BigEndian.Uint64(b[len(b)-8:])
    35  	case reflect.Int8:
    36  		return int8(b[len(b)-1])
    37  	case reflect.Int16:
    38  		return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
    39  	case reflect.Int32:
    40  		return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
    41  	case reflect.Int64:
    42  		return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
    43  	default:
    44  		return new(big.Int).SetBytes(b)
    45  	}
    46  }
    47  
    48  //读BoL
    49  func readBool(word []byte) (bool, error) {
    50  	for _, b := range word[:31] {
    51  		if b != 0 {
    52  			return false, errBadBool
    53  		}
    54  	}
    55  	switch word[31] {
    56  	case 0:
    57  		return false, nil
    58  	case 1:
    59  		return true, nil
    60  	default:
    61  		return false, errBadBool
    62  	}
    63  }
    64  
    65  //函数类型只是在末尾带有函数选择签名的地址。
    66  //这通过始终将其显示为24个数组(address+sig=24字节)来强制执行该标准。
    67  func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
    68  	if t.T != FunctionTy {
    69  		return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array")
    70  	}
    71  	if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 {
    72  		err = fmt.Errorf("abi: got improperly encoded function type, got %v", word)
    73  	} else {
    74  		copy(funcTy[:], word[0:24])
    75  	}
    76  	return
    77  }
    78  
    79  //通过反射,创建要从中读取的固定数组
    80  func readFixedBytes(t Type, word []byte) (interface{}, error) {
    81  	if t.T != FixedBytesTy {
    82  		return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
    83  	}
    84  //转换
    85  	array := reflect.New(t.Type).Elem()
    86  
    87  	reflect.Copy(array, reflect.ValueOf(word[0:t.Size]))
    88  	return array.Interface(), nil
    89  
    90  }
    91  
    92  func getFullElemSize(elem *Type) int {
    93  //所有其他元素都应计为32(切片有指向各个元素的指针)
    94  	size := 32
    95  //数组将其包装,每个元素的大小相同
    96  	for elem.T == ArrayTy {
    97  		size *= elem.Size
    98  		elem = elem.Elem
    99  	}
   100  	return size
   101  }
   102  
   103  //迭代解包元素
   104  func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
   105  	if size < 0 {
   106  		return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
   107  	}
   108  	if start+32*size > len(output) {
   109  		return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
   110  	}
   111  
   112  //此值将成为切片或数组,具体取决于类型
   113  	var refSlice reflect.Value
   114  
   115  	if t.T == SliceTy {
   116  //申报我们的切片
   117  		refSlice = reflect.MakeSlice(t.Type, size, size)
   118  	} else if t.T == ArrayTy {
   119  //声明我们的数组
   120  		refSlice = reflect.New(t.Type).Elem()
   121  	} else {
   122  		return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage")
   123  	}
   124  
   125  //数组具有压缩元素,从而导致较长的解包步骤。
   126  //每个元素的切片只有32个字节(指向内容)。
   127  	elemSize := 32
   128  	if t.T == ArrayTy {
   129  		elemSize = getFullElemSize(t.Elem)
   130  	}
   131  
   132  	for i, j := start, 0; j < size; i, j = i+elemSize, j+1 {
   133  
   134  		inter, err := toGoType(i, *t.Elem, output)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  
   139  //将项目附加到反射切片
   140  		refSlice.Index(j).Set(reflect.ValueOf(inter))
   141  	}
   142  
   143  //返回接口
   144  	return refSlice.Interface(), nil
   145  }
   146  
   147  //togotype解析输出字节并递归地分配这些字节的值
   148  //符合ABI规范的GO类型。
   149  func toGoType(index int, t Type, output []byte) (interface{}, error) {
   150  	if index+32 > len(output) {
   151  		return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
   152  	}
   153  
   154  	var (
   155  		returnOutput []byte
   156  		begin, end   int
   157  		err          error
   158  	)
   159  
   160  //如果需要长度前缀,请查找返回的起始单词和大小。
   161  	if t.requiresLengthPrefix() {
   162  		begin, end, err = lengthPrefixPointsTo(index, output)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  	} else {
   167  		returnOutput = output[index : index+32]
   168  	}
   169  
   170  	switch t.T {
   171  	case SliceTy:
   172  		return forEachUnpack(t, output, begin, end)
   173  	case ArrayTy:
   174  		return forEachUnpack(t, output, index, t.Size)
   175  case StringTy: //变量数组写在返回字节的末尾
   176  		return string(output[begin : begin+end]), nil
   177  	case IntTy, UintTy:
   178  		return readInteger(t.Kind, returnOutput), nil
   179  	case BoolTy:
   180  		return readBool(returnOutput)
   181  	case AddressTy:
   182  		return common.BytesToAddress(returnOutput), nil
   183  	case HashTy:
   184  		return common.BytesToHash(returnOutput), nil
   185  	case BytesTy:
   186  		return output[begin : begin+end], nil
   187  	case FixedBytesTy:
   188  		return readFixedBytes(t, returnOutput)
   189  	case FunctionTy:
   190  		return readFunctionType(t, returnOutput)
   191  	default:
   192  		return nil, fmt.Errorf("abi: unknown type %v", t.T)
   193  	}
   194  }
   195  
   196  //将一个32字节的切片解释为一个偏移量,然后确定要寻找哪一个指示来解码该类型。
   197  func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
   198  	bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
   199  	bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
   200  	outputLength := big.NewInt(int64(len(output)))
   201  
   202  	if bigOffsetEnd.Cmp(outputLength) > 0 {
   203  		return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength)
   204  	}
   205  
   206  	if bigOffsetEnd.BitLen() > 63 {
   207  		return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd)
   208  	}
   209  
   210  	offsetEnd := int(bigOffsetEnd.Uint64())
   211  	lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd])
   212  
   213  	totalSize := big.NewInt(0)
   214  	totalSize.Add(totalSize, bigOffsetEnd)
   215  	totalSize.Add(totalSize, lengthBig)
   216  	if totalSize.BitLen() > 63 {
   217  		return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize)
   218  	}
   219  
   220  	if totalSize.Cmp(outputLength) > 0 {
   221  		return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize)
   222  	}
   223  	start = int(bigOffsetEnd.Uint64())
   224  	length = int(lengthBig.Uint64())
   225  	return
   226  }
   227