|
1 |
| -// Copyright 2016 The go-ethereum Authors |
| 1 | +// Copyright 2021 The go-ethereum Authors |
2 | 2 | // This file is part of the go-ethereum library.
|
3 | 3 | //
|
4 | 4 | // The go-ethereum library is free software: you can redistribute it and/or modify
|
|
17 | 17 | package abi
|
18 | 18 |
|
19 | 19 | import (
|
| 20 | + "bytes" |
20 | 21 | "errors"
|
21 | 22 | "fmt"
|
22 |
| - "reflect" |
23 |
| -) |
| 23 | + "strings" |
24 | 24 |
|
25 |
| -var ( |
26 |
| - errBadBool = errors.New("abi: improperly encoded boolean value") |
| 25 | + "github.com/ethereum/go-ethereum/common" |
| 26 | + "github.com/ethereum/go-ethereum/crypto" |
27 | 27 | )
|
28 | 28 |
|
29 |
| -// formatSliceString formats the reflection kind with the given slice size |
30 |
| -// and returns a formatted string representation. |
31 |
| -func formatSliceString(kind reflect.Kind, sliceSize int) string { |
32 |
| - if sliceSize == -1 { |
33 |
| - return fmt.Sprintf("[]%v", kind) |
34 |
| - } |
35 |
| - return fmt.Sprintf("[%d]%v", sliceSize, kind) |
| 29 | +type Error struct { |
| 30 | + Name string |
| 31 | + Inputs Arguments |
| 32 | + str string |
| 33 | + // Sig contains the string signature according to the ABI spec. |
| 34 | + // e.g. event foo(uint32 a, int b) = "foo(uint32,int256)" |
| 35 | + // Please note that "int" is substitute for its canonical representation "int256" |
| 36 | + Sig string |
| 37 | + // ID returns the canonical representation of the event's signature used by the |
| 38 | + // abi definition to identify event names and types. |
| 39 | + ID common.Hash |
36 | 40 | }
|
37 | 41 |
|
38 |
| -// sliceTypeCheck checks that the given slice can by assigned to the reflection |
39 |
| -// type in t. |
40 |
| -func sliceTypeCheck(t Type, val reflect.Value) error { |
41 |
| - if val.Kind() != reflect.Slice && val.Kind() != reflect.Array { |
42 |
| - return typeErr(formatSliceString(t.GetType().Kind(), t.Size), val.Type()) |
| 42 | +func NewError(name string, inputs Arguments) Error { |
| 43 | + // sanitize inputs to remove inputs without names |
| 44 | + // and precompute string and sig representation. |
| 45 | + names := make([]string, len(inputs)) |
| 46 | + types := make([]string, len(inputs)) |
| 47 | + for i, input := range inputs { |
| 48 | + if input.Name == "" { |
| 49 | + inputs[i] = Argument{ |
| 50 | + Name: fmt.Sprintf("arg%d", i), |
| 51 | + Indexed: input.Indexed, |
| 52 | + Type: input.Type, |
| 53 | + } |
| 54 | + } else { |
| 55 | + inputs[i] = input |
| 56 | + } |
| 57 | + // string representation |
| 58 | + names[i] = fmt.Sprintf("%v %v", input.Type, inputs[i].Name) |
| 59 | + if input.Indexed { |
| 60 | + names[i] = fmt.Sprintf("%v indexed %v", input.Type, inputs[i].Name) |
| 61 | + } |
| 62 | + // sig representation |
| 63 | + types[i] = input.Type.String() |
43 | 64 | }
|
44 | 65 |
|
45 |
| - if t.T == ArrayTy && val.Len() != t.Size { |
46 |
| - return typeErr(formatSliceString(t.Elem.GetType().Kind(), t.Size), formatSliceString(val.Type().Elem().Kind(), val.Len())) |
47 |
| - } |
| 66 | + str := fmt.Sprintf("error %v(%v)", name, strings.Join(names, ", ")) |
| 67 | + sig := fmt.Sprintf("%v(%v)", name, strings.Join(types, ",")) |
| 68 | + id := common.BytesToHash(crypto.Keccak256([]byte(sig))) |
48 | 69 |
|
49 |
| - if t.Elem.T == SliceTy || t.Elem.T == ArrayTy { |
50 |
| - if val.Len() > 0 { |
51 |
| - return sliceTypeCheck(*t.Elem, val.Index(0)) |
52 |
| - } |
| 70 | + return Error{ |
| 71 | + Name: name, |
| 72 | + Inputs: inputs, |
| 73 | + str: str, |
| 74 | + Sig: sig, |
| 75 | + ID: id, |
53 | 76 | }
|
| 77 | +} |
54 | 78 |
|
55 |
| - if val.Type().Elem().Kind() != t.Elem.GetType().Kind() { |
56 |
| - return typeErr(formatSliceString(t.Elem.GetType().Kind(), t.Size), val.Type()) |
57 |
| - } |
58 |
| - return nil |
| 79 | +func (e *Error) String() string { |
| 80 | + return e.str |
59 | 81 | }
|
60 | 82 |
|
61 |
| -// typeCheck checks that the given reflection value can be assigned to the reflection |
62 |
| -// type in t. |
63 |
| -func typeCheck(t Type, value reflect.Value) error { |
64 |
| - if t.T == SliceTy || t.T == ArrayTy { |
65 |
| - return sliceTypeCheck(t, value) |
| 83 | +func (e *Error) Unpack(data []byte) (interface{}, error) { |
| 84 | + if len(data) < 4 { |
| 85 | + return "", errors.New("invalid data for unpacking") |
66 | 86 | }
|
67 |
| - |
68 |
| - // Check base type validity. Element types will be checked later on. |
69 |
| - if t.GetType().Kind() != value.Kind() { |
70 |
| - return typeErr(t.GetType().Kind(), value.Kind()) |
71 |
| - } else if t.T == FixedBytesTy && t.Size != value.Len() { |
72 |
| - return typeErr(t.GetType(), value.Type()) |
73 |
| - } else { |
74 |
| - return nil |
| 87 | + if !bytes.Equal(data[:4], e.ID[:4]) { |
| 88 | + return "", errors.New("invalid data for unpacking") |
75 | 89 | }
|
76 |
| - |
77 |
| -} |
78 |
| - |
79 |
| -// typeErr returns a formatted type casting error. |
80 |
| -func typeErr(expected, got interface{}) error { |
81 |
| - return fmt.Errorf("abi: cannot use %v as type %v as argument", got, expected) |
| 90 | + return e.Inputs.Unpack(data[4:]) |
82 | 91 | }
|
0 commit comments