Skip to content

Commit 4dc3ce7

Browse files
committed
Try to fix unpacking to string
1 parent 4c600ec commit 4dc3ce7

File tree

2 files changed

+200
-4
lines changed

2 files changed

+200
-4
lines changed

accounts/abi/type.go

+196
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,166 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
226226
return
227227
}
228228

229+
// NewTypeAsString creates a new reflection type of abi type given in t.
230+
func NewTypeAsString(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) {
231+
// check that array brackets are equal if they exist
232+
if strings.Count(t, "[") != strings.Count(t, "]") {
233+
return Type{}, errors.New("invalid arg type in abi")
234+
}
235+
typ.stringKind = t
236+
237+
// if there are brackets, get ready to go into slice/array mode and
238+
// recursively create the type
239+
if strings.Count(t, "[") != 0 {
240+
// Note internalType can be empty here.
241+
subInternal := internalType
242+
if i := strings.LastIndex(internalType, "["); i != -1 {
243+
subInternal = subInternal[:i]
244+
}
245+
// recursively embed the type
246+
i := strings.LastIndex(t, "[")
247+
embeddedType, err := NewTypeAsString(t[:i], subInternal, components)
248+
if err != nil {
249+
return Type{}, err
250+
}
251+
// grab the last cell and create a type from there
252+
sliced := t[i:]
253+
// grab the slice size with regexp
254+
re := regexp.MustCompile("[0-9]+")
255+
intz := re.FindAllString(sliced, -1)
256+
257+
if len(intz) == 0 {
258+
// is a slice
259+
typ.T = SliceTy
260+
typ.Elem = &embeddedType
261+
typ.stringKind = embeddedType.stringKind + sliced
262+
} else if len(intz) == 1 {
263+
// is an array
264+
typ.T = ArrayTy
265+
typ.Elem = &embeddedType
266+
typ.Size, err = strconv.Atoi(intz[0])
267+
if err != nil {
268+
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
269+
}
270+
typ.stringKind = embeddedType.stringKind + sliced
271+
} else {
272+
return Type{}, errors.New("invalid formatting of array type")
273+
}
274+
return typ, err
275+
}
276+
// parse the type and size of the abi-type.
277+
matches := typeRegex.FindAllStringSubmatch(t, -1)
278+
if len(matches) == 0 {
279+
return Type{}, fmt.Errorf("invalid type '%v'", t)
280+
}
281+
parsedType := matches[0]
282+
283+
// varSize is the size of the variable
284+
var varSize int
285+
if len(parsedType[3]) > 0 {
286+
var err error
287+
varSize, err = strconv.Atoi(parsedType[2])
288+
if err != nil {
289+
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
290+
}
291+
} else {
292+
if parsedType[0] == "uint" || parsedType[0] == "int" {
293+
// this should fail because it means that there's something wrong with
294+
// the abi type (the compiler should always format it to the size...always)
295+
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
296+
}
297+
}
298+
// varType is the parsed abi type
299+
switch varType := parsedType[1]; varType {
300+
case "int":
301+
typ.Size = varSize
302+
typ.T = IntTy
303+
case "uint":
304+
typ.Size = varSize
305+
typ.T = UintTy
306+
case "bool":
307+
typ.T = BoolTy
308+
case "address":
309+
typ.Size = 20
310+
typ.T = AddressTy
311+
case "string":
312+
typ.T = StringTy
313+
case "bytes":
314+
if varSize == 0 {
315+
typ.T = BytesTy
316+
} else {
317+
if varSize > 32 {
318+
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
319+
}
320+
typ.T = FixedBytesTy
321+
typ.Size = varSize
322+
}
323+
case "tuple":
324+
var (
325+
fields []reflect.StructField
326+
elems []*Type
327+
names []string
328+
expression string // canonical parameter expression
329+
used = make(map[string]bool)
330+
)
331+
expression += "("
332+
for idx, c := range components {
333+
cType, err := NewTypeAsString(c.Type, c.InternalType, c.Components)
334+
if err != nil {
335+
return Type{}, err
336+
}
337+
name := ToCamelCase(c.Name)
338+
if name == "" {
339+
return Type{}, errors.New("abi: purely anonymous or underscored field is not supported")
340+
}
341+
fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] })
342+
if err != nil {
343+
return Type{}, err
344+
}
345+
used[fieldName] = true
346+
if !isValidFieldName(fieldName) {
347+
return Type{}, fmt.Errorf("field %d has invalid name", idx)
348+
}
349+
fields = append(fields, reflect.StructField{
350+
Name: fieldName, // reflect.StructOf will panic for any exported field.
351+
Type: cType.GetTypeAsString(),
352+
Tag: reflect.StructTag("json:\"" + c.Name + "\""),
353+
})
354+
elems = append(elems, &cType)
355+
names = append(names, c.Name)
356+
expression += cType.stringKind
357+
if idx != len(components)-1 {
358+
expression += ","
359+
}
360+
}
361+
expression += ")"
362+
363+
typ.TupleType = reflect.StructOf(fields)
364+
typ.TupleElems = elems
365+
typ.TupleRawNames = names
366+
typ.T = TupleTy
367+
typ.stringKind = expression
368+
369+
const structPrefix = "struct "
370+
// After solidity 0.5.10, a new field of abi "internalType"
371+
// is introduced. From that we can obtain the struct name
372+
// user defined in the source code.
373+
if internalType != "" && strings.HasPrefix(internalType, structPrefix) {
374+
// Foo.Bar type definition is not allowed in golang,
375+
// convert the format to FooBar
376+
typ.TupleRawName = strings.ReplaceAll(internalType[len(structPrefix):], ".", "")
377+
}
378+
379+
case "function":
380+
typ.T = FunctionTy
381+
typ.Size = 24
382+
default:
383+
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
384+
}
385+
386+
return
387+
}
388+
229389
// GetType returns the reflection type of the ABI type.
230390
func (t Type) GetType() reflect.Type {
231391
switch t.T {
@@ -262,6 +422,42 @@ func (t Type) GetType() reflect.Type {
262422
}
263423
}
264424

425+
// GetTypeAsString returns the reflection type of the ABI type (always string).
426+
func (t Type) GetTypeAsString() reflect.Type {
427+
switch t.T {
428+
case IntTy:
429+
return reflect.TypeOf("")
430+
case UintTy:
431+
return reflect.TypeOf("")
432+
case BoolTy:
433+
return reflect.TypeOf("")
434+
case StringTy:
435+
return reflect.TypeOf("")
436+
case SliceTy:
437+
return reflect.SliceOf(t.Elem.GetTypeAsString())
438+
case ArrayTy:
439+
return reflect.ArrayOf(t.Size, t.Elem.GetTypeAsString())
440+
case TupleTy:
441+
return t.TupleType
442+
case AddressTy:
443+
return reflect.TypeOf("")
444+
case FixedBytesTy:
445+
return reflect.TypeOf("")
446+
case BytesTy:
447+
return reflect.TypeOf("")
448+
case HashTy:
449+
// hashtype currently not used
450+
return reflect.TypeOf("")
451+
case FixedPointTy:
452+
// fixedpoint type currently not used
453+
return reflect.TypeOf("")
454+
case FunctionTy:
455+
return reflect.TypeOf("")
456+
default:
457+
panic("Invalid type")
458+
}
459+
}
460+
265461
// String implements Stringer.
266462
func (t Type) String() (out string) {
267463
return t.stringKind

accounts/abi/unpack.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var (
3232
// MaxUint256 is the maximum value that can be represented by a uint256.
3333
MaxUint256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
3434
// MaxInt256 is the maximum value that can be represented by a int256.
35-
MaxInt256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 255), common.Big1)
35+
//MaxInt256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 255), common.Big1)
3636
)
3737

3838
// ReadInteger reads the integer based on its kind and returns the appropriate value.
@@ -203,10 +203,10 @@ func forEachUnpackAsString(t Type, output []byte, start, size int) (interface{},
203203

204204
if t.T == SliceTy {
205205
// declare our slice
206-
refSlice = reflect.MakeSlice(t.GetType(), size, size)
206+
refSlice = reflect.MakeSlice(t.GetTypeAsString(), size, size)
207207
} else if t.T == ArrayTy {
208208
// declare our array
209-
refSlice = reflect.New(t.GetType()).Elem()
209+
refSlice = reflect.New(t.GetTypeAsString()).Elem()
210210
} else {
211211
return nil, errors.New("abi: invalid type in array/slice unpacking stage")
212212
}
@@ -260,7 +260,7 @@ func forTupleUnpack(t Type, output []byte) (interface{}, error) {
260260
}
261261

262262
func forTupleUnpackAsString(t Type, output []byte) (interface{}, error) {
263-
retval := reflect.New(t.GetType()).Elem()
263+
retval := reflect.New(t.GetTypeAsString()).Elem()
264264
virtualArgs := 0
265265
for index, elem := range t.TupleElems {
266266
marshalledValue, err := toString((index+virtualArgs)*32, *elem, output)

0 commit comments

Comments
 (0)