mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
accounts/abi: added FunctionType enumeration
This commit is contained in:
parent
6b6c912462
commit
da57a13e20
4 changed files with 45 additions and 25 deletions
|
|
@ -139,18 +139,18 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
switch field.Type {
|
switch field.Type {
|
||||||
case "constructor":
|
case "constructor":
|
||||||
abi.Constructor = NewMethod("", "", field.StateMutability, field.Constant, field.Payable, false, false, field.Inputs, nil)
|
abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.Payable, field.Inputs, nil)
|
||||||
// empty defaults to function according to the abi spec
|
// empty defaults to function according to the abi spec
|
||||||
case "function":
|
case "function":
|
||||||
name := abi.methodName(field.Name)
|
name := abi.methodName(field.Name)
|
||||||
abi.Methods[name] = NewMethod(name, field.Name, field.StateMutability, field.Constant, field.Payable, false, false, field.Inputs, field.Outputs)
|
abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constant, field.Payable, field.Inputs, field.Outputs)
|
||||||
case "fallback":
|
case "fallback":
|
||||||
// New introduced function type in v0.6.0, check more detail
|
// New introduced function type in v0.6.0, check more detail
|
||||||
// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
|
// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
|
||||||
if abi.HasFallback() {
|
if abi.HasFallback() {
|
||||||
return errors.New("only single fallback is allowed")
|
return errors.New("only single fallback is allowed")
|
||||||
}
|
}
|
||||||
abi.Fallback = NewMethod("", "", field.StateMutability, field.Constant, field.Payable, true, false, nil, nil)
|
abi.Fallback = NewMethod("", "", Fallback, field.StateMutability, field.Constant, field.Payable, nil, nil)
|
||||||
case "receive":
|
case "receive":
|
||||||
// New introduced function type in v0.6.0, check more detail
|
// New introduced function type in v0.6.0, check more detail
|
||||||
// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
|
// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
|
||||||
|
|
@ -160,7 +160,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||||
if field.StateMutability != "payable" {
|
if field.StateMutability != "payable" {
|
||||||
return errors.New("the statemutability of receive can only be payable")
|
return errors.New("the statemutability of receive can only be payable")
|
||||||
}
|
}
|
||||||
abi.Receive = NewMethod("", "", field.StateMutability, field.Constant, field.Payable, false, true, nil, nil)
|
abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable, nil, nil)
|
||||||
case "event":
|
case "event":
|
||||||
name := abi.eventName(field.Name)
|
name := abi.eventName(field.Name)
|
||||||
abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs)
|
abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs)
|
||||||
|
|
@ -226,10 +226,10 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
|
||||||
|
|
||||||
// HasFallback returns an indicator whether a fallback function is included.
|
// HasFallback returns an indicator whether a fallback function is included.
|
||||||
func (abi *ABI) HasFallback() bool {
|
func (abi *ABI) HasFallback() bool {
|
||||||
return abi.Fallback.IsFallback
|
return abi.Fallback.Type == Fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasReceive returns an indicator whether a receive function is included.
|
// HasReceive returns an indicator whether a receive function is included.
|
||||||
func (abi *ABI) HasReceive() bool {
|
func (abi *ABI) HasReceive() bool {
|
||||||
return abi.Receive.IsReceive
|
return abi.Receive.Type == Receive
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ func TestReader(t *testing.T) {
|
||||||
Uint256, _ := NewType("uint256", "", nil)
|
Uint256, _ := NewType("uint256", "", nil)
|
||||||
abi := ABI{
|
abi := ABI{
|
||||||
Methods: map[string]Method{
|
Methods: map[string]Method{
|
||||||
"balance": NewMethod("balance", "balance", "view", true, false, false, false, nil, nil),
|
"balance": NewMethod("balance", "balance", Function, "view", false, false, nil, nil),
|
||||||
"send": NewMethod("send", "send", "", false, false, false, false, []Argument{{"amount", Uint256, false}}, nil),
|
"send": NewMethod("send", "send", Function, "", false, false, []Argument{{"amount", Uint256, false}}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ func TestTestSlice(t *testing.T) {
|
||||||
|
|
||||||
func TestMethodSignature(t *testing.T) {
|
func TestMethodSignature(t *testing.T) {
|
||||||
String, _ := NewType("string", "", nil)
|
String, _ := NewType("string", "", nil)
|
||||||
m := NewMethod("foo", "foo", "", false, false, false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
|
m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
|
||||||
exp := "foo(string,string)"
|
exp := "foo(string,string)"
|
||||||
if m.Sig != exp {
|
if m.Sig != exp {
|
||||||
t.Error("signature mismatch", exp, "!=", m.Sig)
|
t.Error("signature mismatch", exp, "!=", m.Sig)
|
||||||
|
|
@ -179,7 +179,7 @@ func TestMethodSignature(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uintt, _ := NewType("uint256", "", nil)
|
uintt, _ := NewType("uint256", "", nil)
|
||||||
m = NewMethod("foo", "foo", "", false, false, false, false, []Argument{{"bar", uintt, false}}, nil)
|
m = NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", uintt, false}}, nil)
|
||||||
exp = "foo(uint256)"
|
exp = "foo(uint256)"
|
||||||
if m.Sig != exp {
|
if m.Sig != exp {
|
||||||
t.Error("signature mismatch", exp, "!=", m.Sig)
|
t.Error("signature mismatch", exp, "!=", m.Sig)
|
||||||
|
|
@ -198,7 +198,7 @@ func TestMethodSignature(t *testing.T) {
|
||||||
{Name: "y", Type: "int256"},
|
{Name: "y", Type: "int256"},
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
m = NewMethod("foo", "foo", "", false, false, false, false, []Argument{{"s", s, false}, {"bar", String, false}}, nil)
|
m = NewMethod("foo", "foo", Function, "", false, false, []Argument{{"s", s, false}, {"bar", String, false}}, nil)
|
||||||
exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)"
|
exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)"
|
||||||
if m.Sig != exp {
|
if m.Sig != exp {
|
||||||
t.Error("signature mismatch", exp, "!=", m.Sig)
|
t.Error("signature mismatch", exp, "!=", m.Sig)
|
||||||
|
|
|
||||||
|
|
@ -639,9 +639,9 @@ func formatMethod(method abi.Method, structs map[string]*tmplStruct) string {
|
||||||
state = state + " "
|
state = state + " "
|
||||||
}
|
}
|
||||||
identity := fmt.Sprintf("function %v", method.RawName)
|
identity := fmt.Sprintf("function %v", method.RawName)
|
||||||
if method.IsFallback {
|
if method.Type == abi.Fallback {
|
||||||
identity = "fallback"
|
identity = "fallback"
|
||||||
} else if method.IsReceive {
|
} else if method.Type == abi.Receive {
|
||||||
identity = "receive"
|
identity = "receive"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s(%v) %sreturns(%v)", identity, strings.Join(inputs, ", "), state, strings.Join(outputs, ", "))
|
return fmt.Sprintf("%s(%v) %sreturns(%v)", identity, strings.Join(inputs, ", "), state, strings.Join(outputs, ", "))
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,24 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FunctionType represents different types of functions a contract might have.
|
||||||
|
type FunctionType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Constructor represents the constructor of the contract.
|
||||||
|
// The constructor function is called while deploying a contract.
|
||||||
|
Constructor FunctionType = iota
|
||||||
|
// Fallback represents the fallback function.
|
||||||
|
// This function is executed if no other function matches the given function
|
||||||
|
// signature and no receive function is specified.
|
||||||
|
Fallback
|
||||||
|
// Receive represents the receive function.
|
||||||
|
// This function is executed on plain Ether transfers.
|
||||||
|
Receive
|
||||||
|
// Function represents a normal function.
|
||||||
|
Function
|
||||||
|
)
|
||||||
|
|
||||||
// Method represents a callable given a `Name` and whether the method is a constant.
|
// Method represents a callable given a `Name` and whether the method is a constant.
|
||||||
// If the method is `Const` no transaction needs to be created for this
|
// If the method is `Const` no transaction needs to be created for this
|
||||||
// particular Method call. It can easily be simulated using a local VM.
|
// particular Method call. It can easily be simulated using a local VM.
|
||||||
|
|
@ -44,6 +62,10 @@ type Method struct {
|
||||||
Name string
|
Name string
|
||||||
RawName string // RawName is the raw method name parsed from ABI
|
RawName string // RawName is the raw method name parsed from ABI
|
||||||
|
|
||||||
|
// Type indicates whether the method is a
|
||||||
|
// special fallback introduced in solidity v0.6.0
|
||||||
|
Type FunctionType
|
||||||
|
|
||||||
// StateMutability indicates the mutability state of method,
|
// StateMutability indicates the mutability state of method,
|
||||||
// the default value is nonpayable. It can be empty if the abi
|
// the default value is nonpayable. It can be empty if the abi
|
||||||
// is generated by legacy compiler.
|
// is generated by legacy compiler.
|
||||||
|
|
@ -53,11 +75,6 @@ type Method struct {
|
||||||
Constant bool
|
Constant bool
|
||||||
Payable bool
|
Payable bool
|
||||||
|
|
||||||
// The following two flags indicates whether the method is a
|
|
||||||
// special fallback introduced in solidity v0.6.0
|
|
||||||
IsFallback bool
|
|
||||||
IsReceive bool
|
|
||||||
|
|
||||||
Inputs Arguments
|
Inputs Arguments
|
||||||
Outputs Arguments
|
Outputs Arguments
|
||||||
str string
|
str string
|
||||||
|
|
@ -74,8 +91,7 @@ type Method struct {
|
||||||
// A method should always be created using NewMethod.
|
// A method should always be created using NewMethod.
|
||||||
// It also precomputes the sig representation and the string representation
|
// It also precomputes the sig representation and the string representation
|
||||||
// of the method.
|
// of the method.
|
||||||
// A method should always be created using NewMethod.
|
func NewMethod(name string, rawName string, funType FunctionType, mutability string, isConst, isPayable bool, inputs Arguments, outputs Arguments) Method {
|
||||||
func NewMethod(name string, rawName string, mutability string, isConst, isPayable, isFallback, isReceive bool, inputs Arguments, outputs Arguments) Method {
|
|
||||||
// inputs
|
// inputs
|
||||||
inputNames := make([]string, len(inputs))
|
inputNames := make([]string, len(inputs))
|
||||||
types := make([]string, len(inputs))
|
types := make([]string, len(inputs))
|
||||||
|
|
@ -91,6 +107,8 @@ func NewMethod(name string, rawName string, mutability string, isConst, isPayabl
|
||||||
outputNames[i] += fmt.Sprintf(" %v", output.Name)
|
outputNames[i] += fmt.Sprintf(" %v", output.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// calculate the signature.
|
||||||
|
sig := fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
|
||||||
// Extract meaningful state mutability of solidity method.
|
// Extract meaningful state mutability of solidity method.
|
||||||
// If it's default value, never print it.
|
// If it's default value, never print it.
|
||||||
state := mutability
|
state := mutability
|
||||||
|
|
@ -101,24 +119,26 @@ func NewMethod(name string, rawName string, mutability string, isConst, isPayabl
|
||||||
state = state + " "
|
state = state + " "
|
||||||
}
|
}
|
||||||
identity := fmt.Sprintf("function %v", rawName)
|
identity := fmt.Sprintf("function %v", rawName)
|
||||||
if isFallback {
|
if funType == Fallback {
|
||||||
identity = "fallback"
|
identity = "fallback"
|
||||||
} else if isReceive {
|
// The fallback function does not have any meaningful signature.
|
||||||
|
sig = ""
|
||||||
|
} else if funType == Receive {
|
||||||
identity = "receive"
|
identity = "receive"
|
||||||
|
// The receive function does not have any meaningful signature.
|
||||||
|
sig = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", "))
|
str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", "))
|
||||||
sig := fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
|
|
||||||
id := crypto.Keccak256([]byte(sig))[:4]
|
id := crypto.Keccak256([]byte(sig))[:4]
|
||||||
|
|
||||||
method := Method{
|
method := Method{
|
||||||
Name: name,
|
Name: name,
|
||||||
RawName: rawName,
|
RawName: rawName,
|
||||||
|
Type: funType,
|
||||||
StateMutability: mutability,
|
StateMutability: mutability,
|
||||||
Constant: isConst,
|
Constant: isConst,
|
||||||
Payable: isPayable,
|
Payable: isPayable,
|
||||||
IsFallback: isFallback,
|
|
||||||
IsReceive: isReceive,
|
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
Outputs: outputs,
|
Outputs: outputs,
|
||||||
str: str,
|
str: str,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue