github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/accounts/abi/table.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "errors" 21 "fmt" 22 "reflect" 23 ) 24 25 // Table represents a go struct and is used so as to convert data passed from solidity. 26 // Input specifies the required struct fields. 27 type Table struct { 28 Name string 29 Inputs Arguments 30 } 31 32 // Unpack performs the operation hexdata -> Go format 33 func (table Table) GetTableInstance() (interface{}, error) { 34 var abi2interfaceReflect []reflect.StructField 35 for i, arg := range table.Inputs { 36 if ToCamelCase(arg.Name) == "" { 37 return nil, errors.New("abi: purely anonymous or underscored field is not supported") 38 } 39 40 sf := reflect.StructField{ 41 Name: ToCamelCase(arg.Name), 42 Type: arg.Type.Type, 43 Index: []int{i}, 44 } 45 abi2interfaceReflect = append(abi2interfaceReflect, sf) 46 } 47 48 st := reflect.StructOf(abi2interfaceReflect) 49 so := reflect.New(st) 50 return so.Interface(), nil 51 } 52 53 // Unpack performs the operation hexdata -> Go format 54 func (table Table) UnpackSingle(v interface{}, field string, data []byte) (interface{}, error) { 55 if reflect.Ptr != reflect.ValueOf(v).Kind() { 56 return nil, fmt.Errorf("abi: Unpack(non-pointer %T)", v) 57 } 58 59 for _, arg := range table.Inputs { 60 if arg.Name != field { 61 continue 62 } 63 64 elem := reflect.ValueOf(v).Elem() 65 66 marshalledValue, err := toGoType(0, arg.Type, data) 67 if err != nil { 68 return nil, err 69 } 70 71 fieldName := ToCamelCase(field) 72 if fieldName == "" { 73 return nil, errors.New("abi: purely anonymous or underscored field is not supported") 74 } 75 76 elem.FieldByName(fieldName).Set(reflect.ValueOf(marshalledValue)) 77 78 return marshalledValue, nil 79 } 80 81 return nil, nil 82 } 83 84 // Pack performs the operation Go format -> Hexdata 85 func (table Table) Pack(args ...interface{}) ([]byte, error) { 86 v := args[0] 87 88 value := reflect.Indirect(reflect.ValueOf(v)) 89 90 // variable input is the output appended at the end of packed 91 // output. This is used for strings and bytes types input. 92 var variableInput []byte 93 94 // input offset is the bytes offset for packed output 95 inputOffset := 0 96 for _, input := range table.Inputs { 97 inputOffset += getTypeSize(input.Type) 98 } 99 100 var ret []byte 101 for _, input := range table.Inputs { 102 fv := value.FieldByName(input.Name) 103 packed, err := input.Type.pack(fv) 104 if err != nil { 105 return nil, err 106 } 107 // check for dynamic types 108 if isDynamicType(input.Type) { 109 // set the offset 110 ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) 111 // calculate next offset 112 inputOffset += len(packed) 113 // append to variable input 114 variableInput = append(variableInput, packed...) 115 } else { 116 // append the packed value to the input 117 ret = append(ret, packed...) 118 } 119 } 120 // append the variable input at the end of the packed input 121 ret = append(ret, variableInput...) 122 123 return ret, nil 124 }