forked from cerc-io/plugeth
08e782c61f
This is the initial step for support of Solidity errors in contract bindings. As of this change, errors can be decoded, but are not supported in bindings yet. Closes #23157
92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
// Copyright 2021 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package abi
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
)
|
|
|
|
type Error struct {
|
|
Name string
|
|
Inputs Arguments
|
|
str string
|
|
// Sig contains the string signature according to the ABI spec.
|
|
// e.g. event foo(uint32 a, int b) = "foo(uint32,int256)"
|
|
// Please note that "int" is substitute for its canonical representation "int256"
|
|
Sig string
|
|
// ID returns the canonical representation of the event's signature used by the
|
|
// abi definition to identify event names and types.
|
|
ID common.Hash
|
|
}
|
|
|
|
func NewError(name string, inputs Arguments) Error {
|
|
// sanitize inputs to remove inputs without names
|
|
// and precompute string and sig representation.
|
|
names := make([]string, len(inputs))
|
|
types := make([]string, len(inputs))
|
|
for i, input := range inputs {
|
|
if input.Name == "" {
|
|
inputs[i] = Argument{
|
|
Name: fmt.Sprintf("arg%d", i),
|
|
Indexed: input.Indexed,
|
|
Type: input.Type,
|
|
}
|
|
} else {
|
|
inputs[i] = input
|
|
}
|
|
// string representation
|
|
names[i] = fmt.Sprintf("%v %v", input.Type, inputs[i].Name)
|
|
if input.Indexed {
|
|
names[i] = fmt.Sprintf("%v indexed %v", input.Type, inputs[i].Name)
|
|
}
|
|
// sig representation
|
|
types[i] = input.Type.String()
|
|
}
|
|
|
|
str := fmt.Sprintf("error %v(%v)", name, strings.Join(names, ", "))
|
|
sig := fmt.Sprintf("%v(%v)", name, strings.Join(types, ","))
|
|
id := common.BytesToHash(crypto.Keccak256([]byte(sig)))
|
|
|
|
return Error{
|
|
Name: name,
|
|
Inputs: inputs,
|
|
str: str,
|
|
Sig: sig,
|
|
ID: id,
|
|
}
|
|
}
|
|
|
|
func (e *Error) String() string {
|
|
return e.str
|
|
}
|
|
|
|
func (e *Error) Unpack(data []byte) (interface{}, error) {
|
|
if len(data) < 4 {
|
|
return "", errors.New("invalid data for unpacking")
|
|
}
|
|
if !bytes.Equal(data[:4], e.ID[:4]) {
|
|
return "", errors.New("invalid data for unpacking")
|
|
}
|
|
return e.Inputs.Unpack(data[4:])
|
|
}
|