From 7f301229bf6c8b4d9e7fc1ca96c87fc468dfa154 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Thu, 19 Dec 2024 17:00:13 +0700 Subject: [PATCH] accounts/abi/bind: make link test case failure output the index of the subtest that failed. --- accounts/abi/bind/bindv2_test.go | 124 +++++++++++++++++++++++++++++ accounts/abi/bind/dep_tree_test.go | 81 ++++++++++++------- 2 files changed, 175 insertions(+), 30 deletions(-) create mode 100644 accounts/abi/bind/bindv2_test.go diff --git a/accounts/abi/bind/bindv2_test.go b/accounts/abi/bind/bindv2_test.go new file mode 100644 index 0000000000..502c57988a --- /dev/null +++ b/accounts/abi/bind/bindv2_test.go @@ -0,0 +1,124 @@ +package bind + +import ( + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/crypto" +) + +type bindV2Test struct { + name string + abis []string + bytecodes []string + types []string + + expectedBindings string +} + +func bind(test *bindV2Test) (bound string, err error) { + var ( + abis []string + bins []string + types []string + ) + libs := make(map[string]string) + for i := 0; i < len(test.types); i++ { + // fully qualified name is of the form : + typeName := test.types[i] + bin := test.bytecodes[i] + abis = append(abis, test.abis[i]) + bins = append(bins, bin) + types = append(types, typeName) + + // Derive the library placeholder which is a 34 character prefix of the + // hex encoding of the keccak256 hash of the fully qualified library name. + // Note that the fully qualified library name is the path of its source + // file and the library name separated by ":". + libPattern := crypto.Keccak256Hash([]byte(typeName)).String()[2:36] // the first 2 chars are 0x + libs[libPattern] = typeName + } + code, err := BindV2(types, abis, bins, "bindv2test", libs, make(map[string]string)) + if err != nil { + return "", fmt.Errorf("error creating bindings: %v", err) + } + + return code, nil +} + +var bindTests2 = []bindV2Test{ + { + "Empty", + []string{`[]`}, + []string{`606060405260068060106000396000f3606060405200`}, + nil, + `// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindv2test + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) +`, + }, + { + "Token", + []string{`[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"spentAllowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]`}, + []string{`60606040526040516107fd3803806107fd83398101604052805160805160a05160c051929391820192909101600160a060020a0333166000908152600360209081526040822086905581548551838052601f6002600019610100600186161502019093169290920482018390047f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390810193919290918801908390106100e857805160ff19168380011785555b506101189291505b8082111561017157600081556001016100b4565b50506002805460ff19168317905550505050610658806101a56000396000f35b828001600101855582156100ac579182015b828111156100ac5782518260005055916020019190600101906100fa565b50508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061017557805160ff19168380011785555b506100c89291506100b4565b5090565b82800160010185558215610165579182015b8281111561016557825182600050559160200191906001019061018756606060405236156100775760e060020a600035046306fdde03811461007f57806323b872dd146100dc578063313ce5671461010e57806370a082311461011a57806395d89b4114610132578063a9059cbb1461018e578063cae9ca51146101bd578063dc3080f21461031c578063dd62ed3e14610341575b610365610002565b61036760008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b6103d5600435602435604435600160a060020a038316600090815260036020526040812054829010156104f357610002565b6103e760025460ff1681565b6103d560043560036020526000908152604090205481565b610367600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b610365600435602435600160a060020a033316600090815260036020526040902054819010156103f157610002565b60806020604435600481810135601f8101849004909302840160405260608381526103d5948235946024803595606494939101919081908382808284375094965050505050505060006000836004600050600033600160a060020a03168152602001908152602001600020600050600087600160a060020a031681526020019081526020016000206000508190555084905080600160a060020a0316638f4ffcb1338630876040518560e060020a0281526004018085600160a060020a0316815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156102f25780820380516001836020036101000a031916815260200191505b50955050505050506000604051808303816000876161da5a03f11561000257505050509392505050565b6005602090815260043560009081526040808220909252602435815220546103d59081565b60046020818152903560009081526040808220909252602435815220546103d59081565b005b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156103c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a03821660009081526040902054808201101561041357610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b820191906000526020600020905b8154815290600101906020018083116104ce57829003601f168201915b505050505081565b600160a060020a03831681526040812054808301101561051257610002565b600160a060020a0380851680835260046020908152604080852033949094168086529382528085205492855260058252808520938552929052908220548301111561055c57610002565b816003600050600086600160a060020a03168152602001908152602001600020600082828250540392505081905550816003600050600085600160a060020a03168152602001908152602001600020600082828250540192505081905550816005600050600086600160a060020a03168152602001908152602001600020600050600033600160a060020a0316815260200190815260200160002060008282825054019250508190555082600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3939250505056`}, + nil, + `// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindv2test + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) +`, + }, +} + +func TestBindingV2(t *testing.T) { + for _, tc := range bindTests2 { + code, err := bind(&tc) + if err != nil { + t.Fatalf("got error from bind: %v", err) + } + if code != tc.expectedBindings { + t.Fatalf("'%s'\n!=\n'%s'\n", code, tc.expectedBindings) + } + } +} diff --git a/accounts/abi/bind/dep_tree_test.go b/accounts/abi/bind/dep_tree_test.go index 2ade604cb9..14aedb6bc0 100644 --- a/accounts/abi/bind/dep_tree_test.go +++ b/accounts/abi/bind/dep_tree_test.go @@ -124,7 +124,7 @@ func __linkDeps(metadata MetaData, depMap map[string]*MetaData, roots *map[strin return linked } -func testLinkCase(t *testing.T, tcInput linkTestCaseInput) { +func testLinkCase(tcInput linkTestCaseInput) error { testAddr := crypto.PubkeyToAddress(testKey.PublicKey) var testAddrNonce uint64 overridesAddrs := make(map[common.Address]struct{}) @@ -159,7 +159,7 @@ func testLinkCase(t *testing.T, tcInput linkTestCaseInput) { var dep common.Address dep.SetBytes(deployer[i : i+20]) if _, ok := overridesAddrs[dep]; !ok { - t.Fatalf("reference to dependent contract that has not yet been deployed: %x\n", dep) + return common.Address{}, nil, fmt.Errorf("reference to dependent contract that has not yet been deployed: %x\n", dep) } } } @@ -190,55 +190,60 @@ func testLinkCase(t *testing.T, tcInput linkTestCaseInput) { deployParams := NewDeploymentParams(contractsList, nil, overrides) res, err := LinkAndDeploy(deployParams, mockDeploy) if err != nil { - t.Fatalf("got error from LinkAndDeploy: %v\n", err) + return err } if len(res.Txs) != len(tcInput.expectDeployed) { - t.Fatalf("got %d deployed contracts. expected %d.\n", len(res.Addrs), len(tcInput.expectDeployed)) + return fmt.Errorf("got %d deployed contracts. expected %d.\n", len(res.Addrs), len(tcInput.expectDeployed)) } for contract, _ := range tcInput.expectDeployed { pattern := crypto.Keccak256Hash([]byte(string(contract))).String()[2:36] if _, ok := res.Addrs[pattern]; !ok { - t.Fatalf("expected contract %s was not deployed\n", string(contract)) + return fmt.Errorf("expected contract %s was not deployed\n", string(contract)) } } + return nil } -func TestContractLinking(t *testing.T) { +var linkTestCases = []linkTestCaseInput{ // test simple contract without any dependencies or overrides - testLinkCase(t, linkTestCaseInput{ + { map[rune][]rune{ 'a': {}}, map[rune]struct{}{}, map[rune]struct{}{ - 'a': {}}}) + 'a': {}}, + }, // test deployment of a contract that depends on somes libraries. - testLinkCase(t, linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}}, map[rune]struct{}{}, map[rune]struct{}{ - 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}}}) + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}}, + }, // test deployment of a contract that depends on some libraries, // one of which has its own library dependencies. - testLinkCase(t, linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'e': {'f', 'g', 'h', 'i'}}, map[rune]struct{}{}, map[rune]struct{}{ - 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}}}) + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}}, + }, // test single contract only without deps - testLinkCase(t, linkTestCaseInput{ + { map[rune][]rune{ 'a': {}}, map[rune]struct{}{}, map[rune]struct{}{ 'a': {}, - }}) + }, + }, // test that libraries at different levels of the tree can share deps, // and that these shared deps will only be deployed once. - testLinkCase(t, linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'e': {'f', 'g', 'h', 'i', 'm'}, @@ -246,56 +251,63 @@ func TestContractLinking(t *testing.T) { map[rune]struct{}{}, map[rune]struct{}{ 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}, 'j': {}, 'k': {}, 'l': {}, 'm': {}, - }}) + }, + }, // test two contracts can be deployed which don't share deps - testLinkCase(t, linkTestCaseInput{ + linkTestCaseInput{ map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'f': {'g', 'h', 'i', 'j'}}, map[rune]struct{}{}, map[rune]struct{}{ 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}, 'j': {}, - }}) + }, + }, // test two contracts can be deployed which share deps - testLinkCase(t, linkTestCaseInput{ + linkTestCaseInput{ map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'f': {'g', 'c', 'd', 'h'}}, map[rune]struct{}{}, map[rune]struct{}{ 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, - }}) + }, + }, // test one contract with overrides for all lib deps - testLinkCase(t, linkTestCaseInput{ + linkTestCaseInput{ map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}}, map[rune]struct{}{'b': {}, 'c': {}, 'd': {}, 'e': {}}, map[rune]struct{}{ - 'a': {}}}) + 'a': {}}, + }, // test one contract with overrides for some lib deps - testLinkCase(t, linkTestCaseInput{ + linkTestCaseInput{ map[rune][]rune{ 'a': {'b', 'c'}}, map[rune]struct{}{'b': {}, 'c': {}}, map[rune]struct{}{ - 'a': {}}}) + 'a': {}}, + }, // test deployment of a contract with overrides - testLinkCase(t, linkTestCaseInput{ + linkTestCaseInput{ map[rune][]rune{ 'a': {}}, map[rune]struct{}{'a': {}}, - map[rune]struct{}{}}) + map[rune]struct{}{}, + }, // two contracts ('a' and 'f') share some dependencies. contract 'a' is marked as an override. expect that any of // its depdencies that aren't shared with 'f' are not deployed. - testLinkCase(t, linkTestCaseInput{map[rune][]rune{ + linkTestCaseInput{map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'f': {'g', 'c', 'd', 'h'}}, map[rune]struct{}{'a': {}}, map[rune]struct{}{ - 'f': {}, 'g': {}, 'c': {}, 'd': {}, 'h': {}}}) + 'f': {}, 'g': {}, 'c': {}, 'd': {}, 'h': {}}, + }, // test nested libraries that share deps at different levels of the tree... with override. // same condition as above test: no sub-dependencies of - testLinkCase(t, linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'e': {'f', 'g', 'h', 'i', 'm'}, @@ -305,5 +317,14 @@ func TestContractLinking(t *testing.T) { 'i': {}, }, map[rune]struct{}{ - 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'm': {}}}) + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'm': {}}, + }, +} + +func TestContractLinking(t *testing.T) { + for i, tc := range linkTestCases { + if err := testLinkCase(tc); err != nil { + t.Fatalf("test case %d failed: %v", i, err) + } + } }