accounts/abi/bind: correctly handle structs used only as constructor params (#23940)
The `structs` map is populated by iterating over all methods except the constructor, which results in a nil-pointer dereference. I've first reproduced the problem with a new test and then implemented the fix. Co-authored-by: Arran Schlosberg <me@arranschlosberg.com>
This commit is contained in:
parent
8fbe0b9b68
commit
b45931cc4a
@ -88,6 +88,13 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||||||
transactIdentifiers = make(map[string]bool)
|
transactIdentifiers = make(map[string]bool)
|
||||||
eventIdentifiers = make(map[string]bool)
|
eventIdentifiers = make(map[string]bool)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for _, input := range evmABI.Constructor.Inputs {
|
||||||
|
if hasStruct(input.Type) {
|
||||||
|
bindStructType[lang](input.Type, structs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, original := range evmABI.Methods {
|
for _, original := range evmABI.Methods {
|
||||||
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
||||||
normalized := original
|
normalized := original
|
||||||
|
@ -1911,6 +1911,50 @@ var bindTests = []struct {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: `ConstructorWithStructParam`,
|
||||||
|
contract: `
|
||||||
|
pragma solidity >=0.8.0 <0.9.0;
|
||||||
|
|
||||||
|
contract ConstructorWithStructParam {
|
||||||
|
struct StructType {
|
||||||
|
uint256 field;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(StructType memory st) {}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
|
||||||
|
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
|
||||||
|
imports: `
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
|
`,
|
||||||
|
tester: `
|
||||||
|
var (
|
||||||
|
key, _ = crypto.GenerateKey()
|
||||||
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
|
)
|
||||||
|
defer sim.Close()
|
||||||
|
|
||||||
|
_, tx, _, err := DeployConstructorWithStructParam(user, sim, ConstructorWithStructParamStructType{Field: big.NewInt(42)})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DeployConstructorWithStructParam() got err %v; want nil err", err)
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
||||||
|
t.Logf("Deployment tx: %+v", tx)
|
||||||
|
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that packages generated by the binder can be successfully compiled and
|
// Tests that packages generated by the binder can be successfully compiled and
|
||||||
@ -1934,22 +1978,23 @@ func TestGolangBindings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// Generate the test suite for all the contracts
|
// Generate the test suite for all the contracts
|
||||||
for i, tt := range bindTests {
|
for i, tt := range bindTests {
|
||||||
var types []string
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if tt.types != nil {
|
var types []string
|
||||||
types = tt.types
|
if tt.types != nil {
|
||||||
} else {
|
types = tt.types
|
||||||
types = []string{tt.name}
|
} else {
|
||||||
}
|
types = []string{tt.name}
|
||||||
// Generate the binding and create a Go source file in the workspace
|
}
|
||||||
bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases)
|
// Generate the binding and create a Go source file in the workspace
|
||||||
if err != nil {
|
bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases)
|
||||||
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
||||||
if err = ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+".go"), []byte(bind), 0600); err != nil {
|
}
|
||||||
t.Fatalf("test %d: failed to write binding: %v", i, err)
|
if err = ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+".go"), []byte(bind), 0600); err != nil {
|
||||||
}
|
t.Fatalf("test %d: failed to write binding: %v", i, err)
|
||||||
// Generate the test file with the injected test code
|
}
|
||||||
code := fmt.Sprintf(`
|
// Generate the test file with the injected test code
|
||||||
|
code := fmt.Sprintf(`
|
||||||
package bindtest
|
package bindtest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -1961,9 +2006,10 @@ func TestGolangBindings(t *testing.T) {
|
|||||||
%s
|
%s
|
||||||
}
|
}
|
||||||
`, tt.imports, tt.name, tt.tester)
|
`, tt.imports, tt.name, tt.tester)
|
||||||
if err := ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), []byte(code), 0600); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), []byte(code), 0600); err != nil {
|
||||||
t.Fatalf("test %d: failed to write tests: %v", i, err)
|
t.Fatalf("test %d: failed to write tests: %v", i, err)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// Convert the package to go modules and use the current source for go-ethereum
|
// Convert the package to go modules and use the current source for go-ethereum
|
||||||
moder := exec.Command(gocmd, "mod", "init", "bindtest")
|
moder := exec.Command(gocmd, "mod", "init", "bindtest")
|
||||||
|
Loading…
Reference in New Issue
Block a user