Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accounts/abi: resolve name conflict for methods starting with a number #26999

Merged
merged 9 commits into from
May 2, 2023

Conversation

MariusVanDerWijden
Copy link
Member

Its a very edge case, but this PR allows abigen to generate bindings for methods starting with a number
closes #26972

@holiman
Copy link
Contributor

holiman commented Mar 28, 2023

// If a method name starts with a number an m is prepended (e.g. 1method -> m1method).

Isn't this just pushing the edgecase a bit further away? What if we already have a method called m1method and 1method ?

EDIT: Ah then we'd get m1method and m1method2.

@MariusVanDerWijden
Copy link
Member Author

The edge case is variables starting with a number, this will crash the abigen. This PR fixes that, so a contract with m1method 1method 1method would create m1method m1method1 m1method2`. So we resolve both the naming conflict and the variable starting with number conflict

func ResolveNameConflict(rawName string, used func(string) bool) string {
name := rawName
if unicode.IsDigit(rune(name[0])) {
name = fmt.Sprintf("%s%s", "m", name)
}
ok := used(name)
for idx := 0; ok; idx++ {
name = fmt.Sprintf("%s%d", rawName, idx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would also need to use the m-prefixed version. So maybe you need to set rawName to name

Copy link
Member Author

@MariusVanDerWijden MariusVanDerWijden Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn now I see it, thanks will add a test

@holiman
Copy link
Contributor

holiman commented Mar 28, 2023

This PR fixes that, so a contract with m1method 1method 1method would create

If you had written a test you'd know that wasn't true :p

Copy link
Contributor

@holiman holiman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@holiman
Copy link
Contributor

holiman commented Mar 29, 2023

--- FAIL: TestReader (0.00s)
panic: runtime error: index out of range [0] with length 0 [recovered]
	panic: runtime error: index out of range [0] with length 0
goroutine 19 [running]:
testing.tRunner.func1.2({0x76e260, 0xc0000c86f0})
	/home/appveyor/.cache/geth-go-1.20.2-linux-amd64/go/src/testing/testing.go:1526 +0x24e
testing.tRunner.func1()
	/home/appveyor/.cache/geth-go-1.20.2-linux-amd64/go/src/testing/testing.go:1529 +0x39f
panic({0x76e260, 0xc0000c86f0})
	/home/appveyor/.cache/geth-go-1.20.2-linux-amd64/go/src/runtime/panic.go:884 +0x213
github.com/ethereum/go-ethereum/accounts/abi.ResolveNameConflict({0x0?, 0xea8?}, 0x1dff?)
	/home/appveyor/projects/go-ethereum/accounts/abi/utils.go:38 +0x1c8
github.com/ethereum/go-ethereum/accounts/abi.(*ABI).UnmarshalJSON(0xc0000e0900, {0xc00012e001, 0xea8, 0x1dff})
	/home/appveyor/projects/go-ethereum/accounts/abi/abi.go:167 +0x73b
encoding/json.(*decodeState).array(0xc0000d8a28, {0x76e8a0?, 0xc0000e0900?, 0xc0000d5240?})

Oops?

accounts/abi/utils.go Outdated Show resolved Hide resolved
MariusVanDerWijden and others added 2 commits March 29, 2023 11:31
Co-authored-by: Martin Holst Swende <martin@swende.se>
@holiman
Copy link
Contributor

holiman commented Mar 30, 2023

--- FAIL: TestCrashers (0.00s)
panic: reflect.StructOf: field "m1" is unexported but missing PkgPath [recovered]
	panic: reflect.StructOf: field "m1" is unexported but missing PkgPath
goroutine 49 [running]:
testing.tRunner.func1.2({0xe2ec80, 0xc00039e910})
	/home/appveyor/.cache/geth-go-1.20.2-linux-amd64/go/src/testing/testing.go:1526 +0x24e
testing.tRunner.func1()
	/home/appveyor/.cache/geth-go-1.20.2-linux-amd64/go/src/testing/testing.go:1529 +0x39f
panic({0xe2ec80, 0xc00039e910})
	/home/appveyor/.cache/geth-go-1.20.2-linux-amd64/go/src/runtime/panic.go:884 +0x213

Copy link
Contributor

@s1na s1na left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@s1na
Copy link
Contributor

s1na commented Apr 5, 2023

Wait, I'm confused:

❯ solc -o build --bin --ast-compact-json --asm --abi --overwrite test.sol
Error: Expected identifier but got 'ILLEGAL'
  --> test.sol:42:14:
   |
42 |     function 1get(uint k) public returns (uint) {
   |              ^

@s1na
Copy link
Contributor

s1na commented Apr 7, 2023

Aha so as @jsvisa mentioned, the problematic pattern is first _ then digit. I wrote a test which should catch it:

diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go
index cbbce7b30..c16f0c752 100644
--- a/accounts/abi/bind/bind_test.go
+++ b/accounts/abi/bind/bind_test.go
@@ -2038,6 +2038,23 @@ var bindTests = []struct {
 				t.Errorf("error deploying the contract: %v", err)
 			}
 		`,
+	}, {
+		name: "NumericMethodName",
+		contract: `
+		// SPDX-License-Identifier: GPL-3.0
+		pragma solidity >=0.4.22 <0.9.0;
+		contract NumericMethodName {
+			function _1test() public pure {}
+		}
+		`,
+		bytecode: []string{"0x6080604052348015600f57600080fd5b50606d80601d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ffa0279514602d575b600080fd5b60336035565b005b56fea2646970667358221220b37b7ec9ac04fb43318f8e3c53ce78e5f4477258cf28f81181359bf8be73c75264736f6c63430008110033"},
+		abi:      []string{`[{"inputs":[],"name":"_1test","outputs":[],"stateMutability":"pure","type":"function"}]`},
+		imports:  ``,
+		tester: `
+			if b, err := NewNumericMethodName(common.Address{}, nil); b == nil || err != nil {
+				t.Fatalf("combined binding (%v) nil or error (%v) not nil", b, nil)
+			}
+`,
 	},
 }
 

@jsvisa
Copy link
Contributor

jsvisa commented Apr 10, 2023

Seems we need to convert field.Name into CamelCase before ResolveNameConflict? eg:

diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index 62b860e18..7a03209f2 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -164,7 +164,8 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
                case "constructor":
                        abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.
                case "function":
-                       name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return
+                       name := ToCamelCase(field.Name)
+                       name = ResolveNameConflict(name, func(s string) bool { _, ok := abi.Methods[s]; return ok })
                        abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constan
                case "fallback":
                        // New introduced function type in v0.6.0, check more detail
@@ -184,7 +185,8 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
                        }
                        abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable,
                case "event":
-                       name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Events[s]; return o
+                       name := ToCamelCase(field.Name)
+                       name = ResolveNameConflict(name, func(s string) bool { _, ok := abi.Events[s]; return ok })
                        abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs)
                case "error":
                        // Errors cannot be overloaded or overridden but are inherited,

@s1na
Copy link
Contributor

s1na commented Apr 24, 2023

I pushed a commit to rather than names starting with digits catch names starting with _%d. Also I've done it during the binding generation. I felt the issue is specifically related to generating Go bindings that crash with leading digit names, and not directly a problem for other ABI operations.

Copy link
Member Author

@MariusVanDerWijden MariusVanDerWijden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I've removed the now obsolete test

@fjl fjl merged commit ac3418d into ethereum:master May 2, 2023
@fjl fjl added this to the 1.11.7 milestone May 2, 2023
shekhirin pushed a commit to shekhirin/go-ethereum that referenced this pull request Jun 6, 2023
ethereum#26999)

This adds logic to prepend 'M' or 'E' to Solidity identifiers when they would
otherwise violate Go identifier naming rules.

Closes ethereum#26972

---------

Co-authored-by: Martin Holst Swende <martin@swende.se>
Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
devopsbo3 pushed a commit to HorizenOfficial/go-ethereum that referenced this pull request Nov 10, 2023
ethereum#26999)

This adds logic to prepend 'M' or 'E' to Solidity identifiers when they would
otherwise violate Go identifier naming rules.

Closes ethereum#26972

---------

Co-authored-by: Martin Holst Swende <martin@swende.se>
Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
devopsbo3 added a commit to HorizenOfficial/go-ethereum that referenced this pull request Nov 10, 2023
devopsbo3 added a commit to HorizenOfficial/go-ethereum that referenced this pull request Nov 10, 2023
@ian0371 ian0371 mentioned this pull request Dec 31, 2024
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

abigen: generate function startswith number
6 participants