accounts/abi, signer/fourbyte: fix incorrect signature

This commit is contained in:
rjl493456442 2019-07-24 15:05:23 +08:00
parent e46a01d56c
commit 29ac361e85
6 changed files with 79 additions and 25 deletions

View file

@ -121,11 +121,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
Inputs []Argument Inputs []Argument
Outputs []Argument Outputs []Argument
} }
if err := json.Unmarshal(data, &fields); err != nil { if err := json.Unmarshal(data, &fields); err != nil {
return err return err
} }
abi.Methods = make(map[string]Method) abi.Methods = make(map[string]Method)
abi.Events = make(map[string]Event) abi.Events = make(map[string]Event)
for _, field := range fields { for _, field := range fields {
@ -144,6 +142,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
} }
abi.Methods[name] = Method{ abi.Methods[name] = Method{
Name: name, Name: name,
RawName: field.Name,
Const: field.Constant, Const: field.Constant,
Inputs: field.Inputs, Inputs: field.Inputs,
Outputs: field.Outputs, Outputs: field.Outputs,
@ -157,6 +156,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
} }
abi.Events[name] = Event{ abi.Events[name] = Event{
Name: name, Name: name,
RawName: field.Name,
Anonymous: field.Anonymous, Anonymous: field.Anonymous,
Inputs: field.Inputs, Inputs: field.Inputs,
} }

View file

@ -61,10 +61,10 @@ func TestReader(t *testing.T) {
exp := ABI{ exp := ABI{
Methods: map[string]Method{ Methods: map[string]Method{
"balance": { "balance": {
"balance", true, nil, nil, "balance", "balance", true, nil, nil,
}, },
"send": { "send": {
"send", false, []Argument{ "send", "send", false, []Argument{
{"amount", Uint256, false}, {"amount", Uint256, false},
}, nil, }, nil,
}, },
@ -162,12 +162,10 @@ func TestTestSlice(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
slice := make([]uint64, 2) slice := make([]uint64, 2)
if _, err := abi.Pack("uint64[2]", slice); err != nil { if _, err := abi.Pack("uint64[2]", slice); err != nil {
t.Error(err) t.Error(err)
} }
if _, err := abi.Pack("uint64[]", slice); err != nil { if _, err := abi.Pack("uint64[]", slice); err != nil {
t.Error(err) t.Error(err)
} }
@ -175,7 +173,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 := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil} m := Method{"foo", "foo", 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())
@ -187,7 +185,7 @@ func TestMethodSignature(t *testing.T) {
} }
uintt, _ := NewType("uint256", nil) uintt, _ := NewType("uint256", nil)
m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil} m = Method{"foo", "foo", 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())
@ -206,13 +204,36 @@ func TestMethodSignature(t *testing.T) {
{Name: "y", Type: "int256"}, {Name: "y", Type: "int256"},
}}, }},
}) })
m = Method{"foo", false, []Argument{{"s", s, false}, {"bar", String, false}}, nil} m = Method{"foo", "foo", 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())
} }
} }
func TestOverloadedMethodSignature(t *testing.T) {
json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`
abi, err := JSON(strings.NewReader(json))
if err != nil {
t.Fatal(err)
}
check := func(name string, expect string, method bool) {
if method {
if abi.Methods[name].Sig() != expect {
t.Fatalf("The signature of overloaded method mismatch, want %s, have %s", expect, abi.Methods[name].Sig())
}
} else {
if abi.Events[name].Sig() != expect {
t.Fatalf("The signature of overloaded event mismatch, want %s, have %s", expect, abi.Events[name].Sig())
}
}
}
check("foo", "foo(uint256,uint256)", true)
check("foo0", "foo(uint256)", true)
check("bar", "bar(uint256)", false)
check("bar0", "bar(uint256,uint256)", false)
}
func TestMultiPack(t *testing.T) { func TestMultiPack(t *testing.T) {
abi, err := JSON(strings.NewReader(jsondata2)) abi, err := JSON(strings.NewReader(jsondata2))
if err != nil { if err != nil {

View file

@ -541,7 +541,7 @@ func formatMethod(method abi.Method, structs map[string]*tmplStruct) string {
if method.Const { if method.Const {
constant = "constant " constant = "constant "
} }
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
} }
// formatEvent transforms raw event representation into a user friendly one. // formatEvent transforms raw event representation into a user friendly one.
@ -554,5 +554,5 @@ func formatEvent(event abi.Event, structs map[string]*tmplStruct) string {
inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name) inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name)
} }
} }
return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", ")) return fmt.Sprintf("event %v(%v)", event.RawName, strings.Join(inputs, ", "))
} }

View file

@ -28,7 +28,19 @@ import (
// holds type information (inputs) about the yielded output. Anonymous events // holds type information (inputs) about the yielded output. Anonymous events
// don't get the signature canonical representation as the first LOG topic. // don't get the signature canonical representation as the first LOG topic.
type Event struct { type Event struct {
// Name the name of the event used for internal representation. which
// It's derived from raw name and will be added suffix when event
// overload occurs.
//
// e.g.
// There are two events have same name:
// * foo(int,int)
// * foo(uint,uint)
// The method name of the first one can be resolved as foo while the
// second one can be resolved as foo0.
Name string Name string
// RawName raw method name parsed from ABI
RawName string
Anonymous bool Anonymous bool
Inputs Arguments Inputs Arguments
} }
@ -41,17 +53,26 @@ func (e Event) String() string {
inputs[i] = fmt.Sprintf("%v indexed %v", input.Type, input.Name) inputs[i] = fmt.Sprintf("%v indexed %v", input.Type, input.Name)
} }
} }
return fmt.Sprintf("event %v(%v)", e.Name, strings.Join(inputs, ", ")) return fmt.Sprintf("event %v(%v)", e.RawName, strings.Join(inputs, ", "))
}
// Sig returns the methods string signature according to the ABI spec.
//
// Example
//
// event foo(uint32 a, int b) = "foo(uint32,int256)"
//
// Please note that "int" is substitute for its canonical representation "int256"
func (e Event) Sig() string {
types := make([]string, len(e.Inputs))
for i, input := range e.Inputs {
types[i] = input.Type.String()
}
return fmt.Sprintf("%v(%v)", e.RawName, strings.Join(types, ","))
} }
// Id returns the canonical representation of the event's signature used by the // Id returns the canonical representation of the event's signature used by the
// abi definition to identify event names and types. // abi definition to identify event names and types.
func (e Event) Id() common.Hash { func (e Event) Id() common.Hash {
types := make([]string, len(e.Inputs)) return common.BytesToHash(crypto.Keccak256([]byte(e.Sig())))
i := 0
for _, input := range e.Inputs {
types[i] = input.Type.String()
i++
}
return common.BytesToHash(crypto.Keccak256([]byte(fmt.Sprintf("%v(%v)", e.Name, strings.Join(types, ",")))))
} }

View file

@ -32,7 +32,19 @@ import (
// be flagged `false`. // be flagged `false`.
// Input specifies the required input parameters for this gives method. // Input specifies the required input parameters for this gives method.
type Method struct { type Method struct {
// Name the name of the method used for internal representation. which
// It's derived from raw name and will be added suffix when function
// overload occurs.
//
// e.g.
// There are two functions have same name:
// * foo(int,int)
// * foo(uint,uint)
// The method name of the first one can be resolved as foo while the
// second one can be resolved as foo0.
Name string Name string
// RawName raw method name parsed from ABI
RawName string
Const bool Const bool
Inputs Arguments Inputs Arguments
Outputs Arguments Outputs Arguments
@ -50,7 +62,7 @@ func (method Method) Sig() string {
for i, input := range method.Inputs { for i, input := range method.Inputs {
types[i] = input.Type.String() types[i] = input.Type.String()
} }
return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ",")) return fmt.Sprintf("%v(%v)", method.RawName, strings.Join(types, ","))
} }
func (method Method) String() string { func (method Method) String() string {
@ -69,7 +81,7 @@ func (method Method) String() string {
if method.Const { if method.Const {
constant = "constant " constant = "constant "
} }
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
} }
func (method Method) Id() []byte { func (method Method) Id() []byte {

View file

@ -140,7 +140,7 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
return nil, err return nil, err
} }
// Everything valid, assemble the call infos for the signer // Everything valid, assemble the call infos for the signer
decoded := decodedCallData{signature: method.Sig(), name: method.Name} decoded := decodedCallData{signature: method.Sig(), name: method.RawName}
for i := 0; i < len(method.Inputs); i++ { for i := 0; i < len(method.Inputs); i++ {
decoded.inputs = append(decoded.inputs, decodedArgument{ decoded.inputs = append(decoded.inputs, decodedArgument{
soltype: method.Inputs[i], soltype: method.Inputs[i],