From 29ac361e858ffc7d15bd7871715392ecc978c630 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 24 Jul 2019 15:05:23 +0800 Subject: [PATCH] accounts/abi, signer/fourbyte: fix incorrect signature --- accounts/abi/abi.go | 4 ++-- accounts/abi/abi_test.go | 35 ++++++++++++++++++++++++++++------- accounts/abi/bind/bind.go | 4 ++-- accounts/abi/event.go | 39 ++++++++++++++++++++++++++++++--------- accounts/abi/method.go | 20 ++++++++++++++++---- signer/fourbyte/abi.go | 2 +- 6 files changed, 79 insertions(+), 25 deletions(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 97a3a98bd3..23b06bb6f1 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -121,11 +121,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { Inputs []Argument Outputs []Argument } - if err := json.Unmarshal(data, &fields); err != nil { return err } - abi.Methods = make(map[string]Method) abi.Events = make(map[string]Event) for _, field := range fields { @@ -144,6 +142,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { } abi.Methods[name] = Method{ Name: name, + RawName: field.Name, Const: field.Constant, Inputs: field.Inputs, Outputs: field.Outputs, @@ -157,6 +156,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { } abi.Events[name] = Event{ Name: name, + RawName: field.Name, Anonymous: field.Anonymous, Inputs: field.Inputs, } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 09d3c94a04..70090a089a 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -61,10 +61,10 @@ func TestReader(t *testing.T) { exp := ABI{ Methods: map[string]Method{ "balance": { - "balance", true, nil, nil, + "balance", "balance", true, nil, nil, }, "send": { - "send", false, []Argument{ + "send", "send", false, []Argument{ {"amount", Uint256, false}, }, nil, }, @@ -162,12 +162,10 @@ func TestTestSlice(t *testing.T) { if err != nil { t.Fatal(err) } - slice := make([]uint64, 2) if _, err := abi.Pack("uint64[2]", slice); err != nil { t.Error(err) } - if _, err := abi.Pack("uint64[]", slice); err != nil { t.Error(err) } @@ -175,7 +173,7 @@ func TestTestSlice(t *testing.T) { func TestMethodSignature(t *testing.T) { 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)" if m.Sig() != exp { t.Error("signature mismatch", exp, "!=", m.Sig()) @@ -187,7 +185,7 @@ func TestMethodSignature(t *testing.T) { } 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)" if m.Sig() != exp { t.Error("signature mismatch", exp, "!=", m.Sig()) @@ -206,13 +204,36 @@ func TestMethodSignature(t *testing.T) { {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)" if m.Sig() != exp { 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) { abi, err := JSON(strings.NewReader(jsondata2)) if err != nil { diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index cd8c942b57..dc51e2a7ec 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -541,7 +541,7 @@ func formatMethod(method abi.Method, structs map[string]*tmplStruct) string { if method.Const { 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. @@ -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) } } - return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", ")) + return fmt.Sprintf("event %v(%v)", event.RawName, strings.Join(inputs, ", ")) } diff --git a/accounts/abi/event.go b/accounts/abi/event.go index 9392c1990c..06d02ffc3f 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -28,7 +28,19 @@ import ( // holds type information (inputs) about the yielded output. Anonymous events // don't get the signature canonical representation as the first LOG topic. type Event struct { - Name string + // 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 + // RawName raw method name parsed from ABI + RawName string Anonymous bool Inputs Arguments } @@ -41,17 +53,26 @@ func (e Event) String() string { 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 // abi definition to identify event names and types. func (e Event) Id() common.Hash { - types := make([]string, len(e.Inputs)) - 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, ","))))) + return common.BytesToHash(crypto.Keccak256([]byte(e.Sig()))) } diff --git a/accounts/abi/method.go b/accounts/abi/method.go index d3c02599f2..d2b3b45a91 100644 --- a/accounts/abi/method.go +++ b/accounts/abi/method.go @@ -32,7 +32,19 @@ import ( // be flagged `false`. // Input specifies the required input parameters for this gives method. type Method struct { - Name string + // 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 + // RawName raw method name parsed from ABI + RawName string Const bool Inputs Arguments Outputs Arguments @@ -42,7 +54,7 @@ type Method struct { // // Example // -// function foo(uint32 a, int b) = "foo(uint32,int256)" +// function foo(uint32 a, int b) = "foo(uint32,int256)" // // Please note that "int" is substitute for its canonical representation "int256" func (method Method) Sig() string { @@ -50,7 +62,7 @@ func (method Method) Sig() string { for i, input := range method.Inputs { 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 { @@ -69,7 +81,7 @@ func (method Method) String() string { if method.Const { 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 { diff --git a/signer/fourbyte/abi.go b/signer/fourbyte/abi.go index ba3af62250..585eae1cd8 100644 --- a/signer/fourbyte/abi.go +++ b/signer/fourbyte/abi.go @@ -140,7 +140,7 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) { return nil, err } // 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++ { decoded.inputs = append(decoded.inputs, decodedArgument{ soltype: method.Inputs[i],