diff --git a/ROADMAP.md b/ROADMAP.md index 15215578e..5c32fd267 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -102,3 +102,16 @@ startup to inform about this, it's very easy to deal with this configuration change, just replace one line. Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release). + +## Services address and port configuration + +Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to +the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof) +that allows to specify several listen addresses/ports using an array of +"address:port" pairs in the service `Addresses` config section. Deprecated +`Address` and `Port` sections of `RPC`, `Prometheus`, `Pprof` subsections of the +`ApplicationConfiguration` as far as the one of RPC server's `TLSConfig` are +still available, but will be removed, so please convert your node configuration +file to use new `Addresses` section for node services. + +Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release). \ No newline at end of file diff --git a/cli/nep_test/nep11_test.go b/cli/nep_test/nep11_test.go index adcc22e29..a8ea2741f 100644 --- a/cli/nep_test/nep11_test.go +++ b/cli/nep_test/nep11_test.go @@ -47,7 +47,7 @@ func TestNEP11Import(t *testing.T) { args := []string{ "neo-go", "wallet", "nep11", "import", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", walletPath, } // missing token hash @@ -123,7 +123,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // transfer funds to contract owner e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--to", nftOwnerAddr, "--token", "GAS", @@ -139,7 +139,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // mint 1 HASHY token by transferring 10 GAS to HASHY contract e.In.WriteString(nftOwnerPass + "\r") e.Run(t, "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wall, "--to", h.StringLE(), "--token", "GAS", @@ -166,7 +166,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // check the balance cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", wall, "--address", nftOwnerAddr} checkBalanceResult := func(t *testing.T, acc string, ids ...[]byte) { @@ -201,7 +201,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // import token e.Run(t, "neo-go", "wallet", "nep11", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wall, "--token", h.StringLE()) @@ -211,7 +211,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // balance check: all accounts e.Run(t, "neo-go", "wallet", "nep11", "balance", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wall, "--token", h.StringLE()) checkBalanceResult(t, nftOwnerAddr, tokenID) @@ -223,7 +223,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // ownerOf: missing contract hash cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdOwnerOf...) cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE()) @@ -238,7 +238,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // tokensOf: missing contract hash cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdTokensOf...) cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE()) @@ -254,7 +254,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // properties: no contract cmdProperties := []string{ "neo-go", "wallet", "nep11", "properties", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdProperties...) cmdProperties = append(cmdProperties, "--token", h.StringLE()) @@ -280,7 +280,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { // tokens: missing contract hash cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdTokens...) cmdTokens = append(cmdTokens, "--token", h.StringLE()) @@ -298,7 +298,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { cmdTransfer := []string{ "neo-go", "wallet", "nep11", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", wall, "--to", testcli.ValidatorAddr, "--from", nftOwnerAddr, @@ -328,7 +328,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) { verifyH := deployVerifyContract(t, e) cmdTransfer = []string{ "neo-go", "wallet", "nep11", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", wall, "--to", verifyH.StringLE(), "--from", nftOwnerAddr, @@ -398,7 +398,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // mint 1.00 NFSO token by transferring 10 GAS to NFSO contract e.In.WriteString(testcli.ValidatorPass + "\r") e.Run(t, "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wall, "--to", h.StringLE(), "--token", "GAS", @@ -432,7 +432,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // check properties e.Run(t, "neo-go", "wallet", "nep11", "properties", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--token", h.StringLE(), "--id", hex.EncodeToString(token1ID)) jProps := e.GetNextLine(t) @@ -449,7 +449,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // check the balance cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", wall, "--address", testcli.ValidatorAddr} checkBalanceResult := func(t *testing.T, acc string, objs ...idAmount) { @@ -481,7 +481,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // import token e.Run(t, "neo-go", "wallet", "nep11", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wall, "--token", h.StringLE()) @@ -500,7 +500,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // ownerOfD: missing contract hash cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdOwnerOf...) cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE()) @@ -515,7 +515,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // tokensOf: missing contract hash cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdTokensOf...) cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE()) @@ -533,7 +533,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // properties: no contract cmdProperties := []string{ "neo-go", "wallet", "nep11", "properties", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdProperties...) cmdProperties = append(cmdProperties, "--token", h.StringLE()) @@ -566,7 +566,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { // tokens: missing contract hash cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], } e.RunWithError(t, cmdTokens...) cmdTokens = append(cmdTokens, "--token", h.StringLE()) @@ -582,7 +582,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { cmdTransfer := []string{ "neo-go", "wallet", "nep11", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", wall, "--to", nftOwnerAddr, "--from", testcli.ValidatorAddr, @@ -612,7 +612,7 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) { verifyH := deployVerifyContract(t, e) cmdTransfer = []string{ "neo-go", "wallet", "nep11", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", wall, "--to", verifyH.StringLE(), "--from", testcli.ValidatorAddr, diff --git a/cli/nep_test/nep17_test.go b/cli/nep_test/nep17_test.go index 6a6a78a1d..5964added 100644 --- a/cli/nep_test/nep17_test.go +++ b/cli/nep_test/nep17_test.go @@ -21,7 +21,7 @@ func TestNEP17Balance(t *testing.T) { e := testcli.NewExecutor(t, true) cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"} cmdbase := append(cmdbalance, - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, ) cmd := append(cmdbase, "--address", testcli.ValidatorAddr) @@ -122,7 +122,7 @@ func TestNEP17Transfer(t *testing.T) { e := testcli.NewExecutor(t, true) args := []string{ "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--to", w.Accounts[0].Address, "--token", "NEO", @@ -182,7 +182,7 @@ func TestNEP17Transfer(t *testing.T) { t.Run("default address", func(t *testing.T) { e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", @@ -208,7 +208,7 @@ func TestNEP17Transfer(t *testing.T) { t.Run("with signers", func(t *testing.T) { e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", @@ -221,7 +221,7 @@ func TestNEP17Transfer(t *testing.T) { validTil := e.Chain.BlockHeight() + 100 cmd := []string{ "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()), "--token", "GAS", @@ -262,7 +262,7 @@ func TestNEP17MultiTransfer(t *testing.T) { require.NoError(t, err) args := []string{ "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", @@ -318,26 +318,26 @@ func TestNEP17ImportToken(t *testing.T) { // missing token hash e.RunWithError(t, "neo-go", "wallet", "nep17", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath) // additional parameter e.RunWithError(t, "neo-go", "wallet", "nep17", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--token", gasContractHash.StringLE(), "useless") e.Run(t, "neo-go", "wallet", "nep17", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--token", gasContractHash.StringLE()) e.Run(t, "neo-go", "wallet", "nep17", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--token", address.Uint160ToString(neoContractHash)) // try address instead of sh // not a NEP-17 token e.RunWithError(t, "neo-go", "wallet", "nep17", "import", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--token", nnsContractHash.StringLE()) diff --git a/cli/options/cli_options_test.go b/cli/options/cli_options_test.go index 4353de239..5ba67a24d 100644 --- a/cli/options/cli_options_test.go +++ b/cli/options/cli_options_test.go @@ -24,7 +24,7 @@ func TestGetRPCClient(t *testing.T) { t.Run("success", func(t *testing.T) { set := flag.NewFlagSet("flagSet", flag.ExitOnError) - set.String(options.RPCEndpointFlag, "http://"+e.RPC.Addr, "") + set.String(options.RPCEndpointFlag, "http://"+e.RPC.Addresses()[0], "") ctx := cli.NewContext(app.New(), set, nil) gctx, _ := options.GetTimeoutContext(ctx) _, ec := options.GetRPCClient(gctx, ctx) diff --git a/cli/query/query_test.go b/cli/query/query_test.go index 0f7bbd4e6..84b58914a 100644 --- a/cli/query/query_test.go +++ b/cli/query/query_test.go @@ -30,7 +30,7 @@ func TestQueryTx(t *testing.T) { transferArgs := []string{ "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--to", w.Accounts[0].Address, "--token", "NEO", @@ -47,7 +47,7 @@ func TestQueryTx(t *testing.T) { tx, ok := e.Chain.GetMemPool().TryGetValue(txHash) require.True(t, ok) - args := []string{"neo-go", "query", "tx", "--rpc-endpoint", "http://" + e.RPC.Addr} + args := []string{"neo-go", "query", "tx", "--rpc-endpoint", "http://" + e.RPC.Addresses()[0]} e.Run(t, append(args, txHash.StringLE())...) e.CheckNextLine(t, `Hash:\s+`+txHash.StringLE()) e.CheckNextLine(t, `OnChain:\s+false`) @@ -74,7 +74,7 @@ func TestQueryTx(t *testing.T) { t.Run("FAULT", func(t *testing.T) { e.In.WriteString("one\r") e.Run(t, "neo-go", "contract", "invokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", @@ -144,7 +144,7 @@ func compareQueryTxVerbose(t *testing.T, e *testcli.Executor, tx *transaction.Tr func TestQueryHeight(t *testing.T) { e := testcli.NewExecutor(t, true) - args := []string{"neo-go", "query", "height", "--rpc-endpoint", "http://" + e.RPC.Addr} + args := []string{"neo-go", "query", "height", "--rpc-endpoint", "http://" + e.RPC.Addresses()[0]} e.Run(t, args...) e.CheckNextLine(t, `^Latest block: [0-9]+$`) e.CheckNextLine(t, `^Validated state: [0-9]+$`) diff --git a/cli/server/server.go b/cli/server/server.go index b48a7ac15..7bd7ebd78 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -141,8 +141,14 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log) go chain.Run() - go prometheus.Start() - go pprof.Start() + err = prometheus.Start() + if err != nil { + return nil, nil, nil, cli.NewExitError(fmt.Errorf("failed to start Prometheus service: %w", err), 1) + } + err = pprof.Start() + if err != nil { + return nil, nil, nil, cli.NewExitError(fmt.Errorf("failed to start Pprof service: %w", err), 1) + } return chain, prometheus, pprof, nil } @@ -540,10 +546,18 @@ Main: } pprof.ShutDown() pprof = metrics.NewPprofService(cfgnew.ApplicationConfiguration.Pprof, log) - go pprof.Start() + err = pprof.Start() + if err != nil { + shutdownErr = fmt.Errorf("failed to start Pprof service: %w", err) + cancel() // Fatal error, like for RPC server. + } prometheus.ShutDown() prometheus = metrics.NewPrometheusService(cfgnew.ApplicationConfiguration.Prometheus, log) - go prometheus.Start() + err = prometheus.Start() + if err != nil { + shutdownErr = fmt.Errorf("failed to start Prometheus service: %w", err) + cancel() // Fatal error, like for RPC server. + } case sigusr1: if oracleSrv != nil { serv.DelService(oracleSrv) @@ -622,14 +636,14 @@ Main: // use global one. So Node and RPC and Prometheus and Pprof will run on one address. func configureAddresses(cfg *config.ApplicationConfiguration) { if cfg.Address != "" { - if cfg.RPC.Address == "" { - cfg.RPC.Address = cfg.Address + if cfg.RPC.Address == nil || *cfg.RPC.Address == "" { + cfg.RPC.Address = &cfg.Address } - if cfg.Prometheus.Address == "" { - cfg.Prometheus.Address = cfg.Address + if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" { + cfg.Prometheus.Address = &cfg.Address } - if cfg.Pprof.Address == "" { - cfg.Pprof.Address = cfg.Address + if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" { + cfg.Pprof.Address = &cfg.Address } } } diff --git a/cli/server/server_test.go b/cli/server/server_test.go index 529bb0878..45307f3f3 100644 --- a/cli/server/server_test.go +++ b/cli/server/server_test.go @@ -321,9 +321,9 @@ func TestConfigureAddresses(t *testing.T) { Address: defaultAddress, } configureAddresses(cfg) - require.Equal(t, defaultAddress, cfg.RPC.Address) - require.Equal(t, defaultAddress, cfg.Prometheus.Address) - require.Equal(t, defaultAddress, cfg.Pprof.Address) + require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated + require.Equal(t, defaultAddress, *cfg.Prometheus.Address) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated + require.Equal(t, defaultAddress, *cfg.Pprof.Address) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated }) t.Run("custom RPC address", func(t *testing.T) { @@ -331,40 +331,40 @@ func TestConfigureAddresses(t *testing.T) { Address: defaultAddress, RPC: config.RPC{ BasicService: config.BasicService{ - Address: customAddress, + Address: &customAddress, }, }, } configureAddresses(cfg) - require.Equal(t, cfg.RPC.Address, customAddress) - require.Equal(t, cfg.Prometheus.Address, defaultAddress) - require.Equal(t, cfg.Pprof.Address, defaultAddress) + require.Equal(t, *cfg.RPC.Address, customAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated + require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated + require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated }) t.Run("custom Pprof address", func(t *testing.T) { cfg := &config.ApplicationConfiguration{ Address: defaultAddress, Pprof: config.BasicService{ - Address: customAddress, + Address: &customAddress, }, } configureAddresses(cfg) - require.Equal(t, cfg.RPC.Address, defaultAddress) - require.Equal(t, cfg.Prometheus.Address, defaultAddress) - require.Equal(t, cfg.Pprof.Address, customAddress) + require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated + require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated + require.Equal(t, *cfg.Pprof.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated }) t.Run("custom Prometheus address", func(t *testing.T) { cfg := &config.ApplicationConfiguration{ Address: defaultAddress, Prometheus: config.BasicService{ - Address: customAddress, + Address: &customAddress, }, } configureAddresses(cfg) - require.Equal(t, cfg.RPC.Address, defaultAddress) - require.Equal(t, cfg.Prometheus.Address, customAddress) - require.Equal(t, cfg.Pprof.Address, defaultAddress) + require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated + require.Equal(t, *cfg.Prometheus.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated + require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated }) } diff --git a/cli/smartcontract/contract_test.go b/cli/smartcontract/contract_test.go index 4d9a8c81c..917f07221 100644 --- a/cli/smartcontract/contract_test.go +++ b/cli/smartcontract/contract_test.go @@ -310,7 +310,7 @@ func TestDeployBigContract(t *testing.T) { e.In.WriteString(testcli.ValidatorPass + "\r") e.RunWithError(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName) } @@ -333,7 +333,7 @@ func TestContractDeployWithData(t *testing.T) { e := testcli.NewExecutor(t, true) cmd := []string{ "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName, "--force", @@ -363,7 +363,7 @@ func TestContractDeployWithData(t *testing.T) { require.NoError(t, err) e.Run(t, "neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], h.StringLE(), "getValueWithKey", "key1", ) @@ -375,7 +375,7 @@ func TestContractDeployWithData(t *testing.T) { require.Equal(t, []byte{12}, res.Stack[0].Value()) e.Run(t, "neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], h.StringLE(), "getValueWithKey", "key2", ) @@ -408,33 +408,33 @@ func TestDeployWithSigners(t *testing.T) { t.Run("missing nef", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", "", "--manifest", manifestName) }) t.Run("missing manifest", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", "") }) t.Run("corrupted data", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName, "[", "str1") }) t.Run("invalid data", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName, "str1", "str2") }) t.Run("missing wallet", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName, "[", "str1", "str2", "]") @@ -447,7 +447,7 @@ func TestDeployWithSigners(t *testing.T) { }) e.In.WriteString(testcli.ValidatorPass + "\r") e.Run(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName, "--force", @@ -534,7 +534,7 @@ func TestContractManifestGroups(t *testing.T) { e.In.WriteString(testcli.ValidatorPass + "\r") e.Run(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", nefName, "--manifest", manifestName, "--force", "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr) @@ -557,22 +557,22 @@ func TestContract_TestInvokeScript(t *testing.T) { t.Run("missing in", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr) + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) }) t.Run("unexisting in", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", badNef) }) t.Run("invalid nef", func(t *testing.T) { require.NoError(t, os.WriteFile(badNef, []byte("qwer"), os.ModePerm)) e.RunWithError(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", badNef) }) t.Run("invalid signers", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", goodNef, "--", "not-a-valid-signer") }) t.Run("no RPC endpoint", func(t *testing.T) { @@ -582,34 +582,34 @@ func TestContract_TestInvokeScript(t *testing.T) { }) t.Run("good", func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", goodNef) }) t.Run("good with hashed signer", func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", goodNef, "--", util.Uint160{1, 2, 3}.StringLE()) }) t.Run("good with addressed signer", func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--in", goodNef, "--", address.Uint160ToString(util.Uint160{1, 2, 3})) }) t.Run("historic, invalid", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--historic", "bad", "--in", goodNef) }) t.Run("historic, index", func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--historic", "0", "--in", goodNef) }) t.Run("historic, hash", func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokescript", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--historic", e.Chain.GetHeaderHash(0).StringLE(), "--in", goodNef) }) @@ -639,7 +639,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { require.NoError(t, err) require.NoError(t, os.WriteFile(configPath, yml, 0666)) e.Run(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, "--force", + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--force", "--wallet-config", configPath, "--address", testcli.ValidatorAddr, "--in", nefName, "--manifest", manifestName) @@ -663,7 +663,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { }) cmd := []string{"neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://" + e.RPC.Addr} + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0]} t.Run("missing hash", func(t *testing.T) { e.RunWithError(t, cmd...) }) @@ -704,7 +704,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { t.Run("real invoke", func(t *testing.T) { cmd := []string{"neo-go", "contract", "invokefunction", - "--rpc-endpoint", "http://" + e.RPC.Addr} + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0]} t.Run("missing wallet", func(t *testing.T) { cmd := append(cmd, h.StringLE(), "getValue") e.RunWithError(t, cmd...) @@ -778,7 +778,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { txout := filepath.Join(tmpDir, "test_contract_tx.json") cmd = []string{"neo-go", "contract", "invokefunction", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--out", txout, "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, } @@ -837,7 +837,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { t.Run("test Storage.Find", func(t *testing.T) { cmd := []string{"neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], h.StringLE(), "testFind"} t.Run("keys only", func(t *testing.T) { @@ -901,7 +901,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { stateBeforeUpdate = mptBeforeUpdate.Root e.In.WriteString("one\r") e.Run(t, "neo-go", "contract", "invokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", h.StringLE(), "update", @@ -913,14 +913,14 @@ func TestComlileAndInvokeFunction(t *testing.T) { indexAfterUpdate = e.Chain.BlockHeight() e.In.WriteString("one\r") e.Run(t, "neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], h.StringLE(), "getValue") checkGetValueOut("on update|sub update") }) t.Run("historic", func(t *testing.T) { t.Run("bad ref", func(t *testing.T) { e.RunWithError(t, "neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--historic", "bad", h.StringLE(), "getValue") }) @@ -931,7 +931,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { } { t.Run(name, func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--historic", ref, h.StringLE(), "getValue") }) @@ -939,7 +939,7 @@ func TestComlileAndInvokeFunction(t *testing.T) { } t.Run("updated historic", func(t *testing.T) { e.Run(t, "neo-go", "contract", "testinvokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--historic", strconv.FormatUint(uint64(indexAfterUpdate), 10), h.StringLE(), "getValue") checkGetValueOut("on update|sub update") diff --git a/cli/wallet/candidate_test.go b/cli/wallet/candidate_test.go index 822d764f4..446b9a82f 100644 --- a/cli/wallet/candidate_test.go +++ b/cli/wallet/candidate_test.go @@ -22,7 +22,7 @@ func TestRegisterCandidate(t *testing.T) { e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", @@ -31,29 +31,29 @@ func TestRegisterCandidate(t *testing.T) { e.CheckTxPersisted(t) e.Run(t, "neo-go", "query", "committee", - "--rpc-endpoint", "http://"+e.RPC.Addr) + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) e.CheckNextLine(t, "^\\s*"+validatorHex) e.Run(t, "neo-go", "query", "candidates", - "--rpc-endpoint", "http://"+e.RPC.Addr) + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) e.CheckNextLine(t, "^\\s*Key.+$") // Header. e.CheckEOF(t) // missing address e.RunWithError(t, "neo-go", "wallet", "candidate", "register", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet) // additional parameter e.RunWithError(t, "neo-go", "wallet", "candidate", "register", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, "error") e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "candidate", "register", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, "--force") @@ -68,14 +68,14 @@ func TestRegisterCandidate(t *testing.T) { t.Run("VoteUnvote", func(t *testing.T) { // positional instead of a flag. e.RunWithError(t, "neo-go", "wallet", "candidate", "vote", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, validatorHex) // not "--candidate hex", but "hex". e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "candidate", "vote", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, "--candidate", validatorHex, @@ -89,18 +89,18 @@ func TestRegisterCandidate(t *testing.T) { require.Equal(t, b, vs[0].Votes) e.Run(t, "neo-go", "query", "committee", - "--rpc-endpoint", "http://"+e.RPC.Addr) + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) e.CheckNextLine(t, "^\\s*"+validatorHex) e.Run(t, "neo-go", "query", "candidates", - "--rpc-endpoint", "http://"+e.RPC.Addr) + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) e.CheckNextLine(t, "^\\s*Key.+$") // Header. e.CheckNextLine(t, "^\\s*"+validatorHex+"\\s*"+b.String()+"\\s*true\\s*true$") e.CheckEOF(t) // check state e.Run(t, "neo-go", "query", "voter", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress) e.CheckNextLine(t, "^\\s*Voted:\\s+"+validatorHex+"\\s+\\("+validatorAddress+"\\)$") e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$") @@ -110,7 +110,7 @@ func TestRegisterCandidate(t *testing.T) { // unvote e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "candidate", "vote", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, "--force") @@ -123,7 +123,7 @@ func TestRegisterCandidate(t *testing.T) { // check state e.Run(t, "neo-go", "query", "voter", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress) e.CheckNextLine(t, "^\\s*Voted:\\s+"+"null") // no vote. e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$") @@ -133,18 +133,18 @@ func TestRegisterCandidate(t *testing.T) { // missing address e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet) // additional argument e.RunWithError(t, "neo-go", "wallet", "candidate", "unregister", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, "argument") e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "candidate", "unregister", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--address", validatorAddress, "--force") @@ -156,7 +156,7 @@ func TestRegisterCandidate(t *testing.T) { // query voter: missing address e.RunWithError(t, "neo-go", "query", "voter") // Excessive parameters. - e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addr, validatorAddress, validatorAddress) - e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addr, "something") - e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addr, "something") + e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress) + e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something") + e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something") } diff --git a/cli/wallet/multisig_test.go b/cli/wallet/multisig_test.go index 0eb3a2219..5972c3659 100644 --- a/cli/wallet/multisig_test.go +++ b/cli/wallet/multisig_test.go @@ -55,7 +55,7 @@ func TestSignMultisigTx(t *testing.T) { // Transfer funds to the multisig. e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", @@ -74,7 +74,7 @@ func TestSignMultisigTx(t *testing.T) { }) e.In.WriteString("pass\r") e.Run(t, "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet1Path, "--from", multisigAddr, "--to", priv.Address(), "--token", "NEO", "--amount", "1", "--out", txPath) @@ -99,7 +99,7 @@ func TestSignMultisigTx(t *testing.T) { // invalid out e.In.WriteString("pass\r") e.RunWithError(t, "neo-go", "wallet", "sign", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet2Path, "--address", multisigAddr, "--in", txPath, "--out", t.TempDir()) @@ -118,7 +118,7 @@ func TestSignMultisigTx(t *testing.T) { }) e.In.WriteString("pass\r") e.Run(t, "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet1Path, "--from", multisigAddr, "--to", priv.Address(), "--token", "NEO", "--amount", "1", "--out", txPath) @@ -152,11 +152,11 @@ func TestSignMultisigTx(t *testing.T) { t.Run("excessive parameters", func(t *testing.T) { e.RunWithError(t, "neo-go", "util", "txdump", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], txPath, "garbage") }) e.Run(t, "neo-go", "util", "txdump", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], txPath) e.CheckTxTestInvokeOutput(t, 11) res := new(result.Invoke) @@ -194,7 +194,7 @@ func TestSignMultisigTx(t *testing.T) { t.Run("sign, save and send", func(t *testing.T) { e.In.WriteString("pass\r") e.Run(t, "neo-go", "wallet", "sign", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet2Path, "--address", multisigAddr, "--in", txPath, "--out", txPath) e.CheckTxPersisted(t) @@ -202,7 +202,7 @@ func TestSignMultisigTx(t *testing.T) { t.Run("double-sign", func(t *testing.T) { e.In.WriteString("pass\r") e.RunWithError(t, "neo-go", "wallet", "sign", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet2Path, "--address", multisigAddr, "--in", txPath, "--out", txPath) }) @@ -217,13 +217,13 @@ func TestSignMultisigTx(t *testing.T) { e.In.WriteString("acc\rpass\rpass\r") e.Run(t, "neo-go", "wallet", "import-deployed", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet1Path, "--wif", simplePriv.WIF(), "--contract", h.StringLE()) e.In.WriteString("pass\r") e.Run(t, "neo-go", "contract", "invokefunction", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet1Path, "--address", multisigHash.StringLE(), // test with scripthash instead of address "--out", txPath, e.Chain.GoverningTokenHash().StringLE(), "transfer", @@ -249,7 +249,7 @@ func TestSignMultisigTx(t *testing.T) { // Contract. e.In.WriteString("pass\r") e.Run(t, "neo-go", "wallet", "sign", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet1Path, "--address", address.Uint160ToString(h), "--in", txPath, "--out", txPath) tx, _ := e.CheckTxPersisted(t) diff --git a/cli/wallet/wallet_test.go b/cli/wallet/wallet_test.go index bfab35d38..27bb4ec98 100644 --- a/cli/wallet/wallet_test.go +++ b/cli/wallet/wallet_test.go @@ -470,17 +470,17 @@ func TestWalletClaimGas(t *testing.T) { t.Run("missing wallet path", func(t *testing.T) { e.RunWithError(t, "neo-go", "wallet", "claim", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--address", testcli.TestWalletAccount) }) t.Run("missing address", func(t *testing.T) { e.RunWithError(t, "neo-go", "wallet", "claim", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.TestWalletPath) }) t.Run("invalid address", func(t *testing.T) { e.RunWithError(t, "neo-go", "wallet", "claim", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.TestWalletPath, "--address", util.Uint160{}.StringLE()) }) @@ -493,14 +493,14 @@ func TestWalletClaimGas(t *testing.T) { t.Run("insufficient funds", func(t *testing.T) { e.In.WriteString("testpass\r") e.RunWithError(t, "neo-go", "wallet", "claim", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount) }) args := []string{ "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", @@ -522,7 +522,7 @@ func TestWalletClaimGas(t *testing.T) { e.In.WriteString("testpass\r") e.Run(t, "neo-go", "wallet", "claim", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount, "--force") @@ -570,7 +570,7 @@ func TestWalletImportDeployed(t *testing.T) { t.Run("unknown contract", func(t *testing.T) { e.In.WriteString("acc\rpass\rpass\r") e.RunWithError(t, "neo-go", "wallet", "import-deployed", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--contract", util.Uint160{}.StringLE(), "--wif", priv.WIF()) }) @@ -578,14 +578,14 @@ func TestWalletImportDeployed(t *testing.T) { badH := deployNNSContract(t, e) // wrong contract with no `verify` method e.In.WriteString("acc\rpass\rpass\r") e.RunWithError(t, "neo-go", "wallet", "import-deployed", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--contract", badH.StringLE(), "--wif", priv.WIF()) }) e.In.WriteString("acc\rpass\rpass\r") e.Run(t, "neo-go", "wallet", "import-deployed", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--wif", priv.WIF(), "--name", "my_acc", "--contract", h.StringLE()) @@ -599,7 +599,7 @@ func TestWalletImportDeployed(t *testing.T) { t.Run("re-importing", func(t *testing.T) { e.In.WriteString("acc\rpass\rpass\r") e.RunWithError(t, "neo-go", "wallet", "import-deployed", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--wif", priv.WIF(), "--name", "my_acc", "--contract", h.StringLE()) }) @@ -607,7 +607,7 @@ func TestWalletImportDeployed(t *testing.T) { t.Run("Sign", func(t *testing.T) { e.In.WriteString("one\r") e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", testcli.ValidatorWallet, "--from", testcli.ValidatorAddr, "--force", "NEO:"+contractAddr+":10", @@ -619,7 +619,7 @@ func TestWalletImportDeployed(t *testing.T) { e.In.WriteString("pass\r") e.Run(t, "neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--from", contractAddr, "--force", "--to", privTo.Address(), "--token", "NEO", "--amount", "1") @@ -680,7 +680,7 @@ func TestOfflineSigning(t *testing.T) { t.Run("1/1 multisig", func(t *testing.T) { args := []string{"neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", walletPath, "--from", testcli.ValidatorAddr, "--to", w.Accounts[0].Address, @@ -699,15 +699,15 @@ func TestOfflineSigning(t *testing.T) { t.Run("sendtx", func(t *testing.T) { // And it can't be sent. e.RunWithError(t, "neo-go", "util", "sendtx", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], txPath) // Even with too many arguments. e.RunWithError(t, "neo-go", "util", "sendtx", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], txPath, txPath) // Or no arguments at all. e.RunWithError(t, "neo-go", "util", "sendtx", - "--rpc-endpoint", "http://"+e.RPC.Addr) + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0]) }) // But it can be signed with a proper wallet. e.In.WriteString("one\r") @@ -716,7 +716,7 @@ func TestOfflineSigning(t *testing.T) { "--in", txPath, "--out", txPath) // And then anyone can send (even via wallet sign). e.Run(t, "neo-go", "wallet", "sign", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", walletPath, "--address", testcli.ValidatorAddr, "--in", txPath) }) @@ -724,7 +724,7 @@ func TestOfflineSigning(t *testing.T) { t.Run("simple signature", func(t *testing.T) { simpleAddr := w.Accounts[0].Address args := []string{"neo-go", "wallet", "nep17", "transfer", - "--rpc-endpoint", "http://" + e.RPC.Addr, + "--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--wallet", walletPath, "--from", simpleAddr, "--to", testcli.ValidatorAddr, @@ -749,7 +749,7 @@ func TestOfflineSigning(t *testing.T) { e.RunWithError(t, "neo-go", "util", "sendtx", txPath) // But it requires no wallet at all. e.Run(t, "neo-go", "util", "sendtx", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], txPath) }) } diff --git a/config/protocol.mainnet.neofs.yml b/config/protocol.mainnet.neofs.yml index c0eaf0743..53a7f05df 100644 --- a/config/protocol.mainnet.neofs.yml +++ b/config/protocol.mainnet.neofs.yml @@ -64,17 +64,21 @@ ApplicationConfiguration: - application/json RPC: Enabled: true + Addresses: + - ":40332" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 40332 TLSConfig: Enabled: false - Port: 40331 + Addresses: + - ":40331" CertFile: serv.crt KeyFile: serv.key Prometheus: Enabled: false - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false - Port: 2113 + Addresses: + - ":2113" diff --git a/config/protocol.mainnet.yml b/config/protocol.mainnet.yml index fcd99245d..bf8bd3aba 100644 --- a/config/protocol.mainnet.yml +++ b/config/protocol.mainnet.yml @@ -82,17 +82,21 @@ ApplicationConfiguration: RPC: Enabled: true + Addresses: + - ":10332" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 10332 TLSConfig: Enabled: false - Port: 10331 + Addresses: + - ":10331" CertFile: serv.crt KeyFile: serv.key Prometheus: Enabled: true - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false - Port: 2113 + Addresses: + - ":2113" diff --git a/config/protocol.privnet.docker.four.yml b/config/protocol.privnet.docker.four.yml index 2a59d1f59..ce60092e5 100644 --- a/config/protocol.privnet.docker.four.yml +++ b/config/protocol.privnet.docker.four.yml @@ -69,15 +69,18 @@ ApplicationConfiguration: Password: "pass" RPC: Enabled: true + Addresses: + - ":30336" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 30336 Prometheus: Enabled: true - Port: 20004 + Addresses: + - ":20004" Pprof: Enabled: false - Port: 20014 + Addresses: + - ":20014" UnlockWallet: Path: "/wallet4.json" Password: "four" diff --git a/config/protocol.privnet.docker.one.yml b/config/protocol.privnet.docker.one.yml index eba250ec0..4a2872d45 100644 --- a/config/protocol.privnet.docker.one.yml +++ b/config/protocol.privnet.docker.one.yml @@ -69,12 +69,14 @@ ApplicationConfiguration: Password: "pass" RPC: Enabled: true + Addresses: + - ":30333" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 30333 Prometheus: Enabled: true - Port: 20001 + Addresses: + - ":20001" Pprof: Enabled: false Port: 20011 diff --git a/config/protocol.privnet.docker.single.yml b/config/protocol.privnet.docker.single.yml index 4582b3cc9..501013752 100644 --- a/config/protocol.privnet.docker.single.yml +++ b/config/protocol.privnet.docker.single.yml @@ -60,15 +60,18 @@ ApplicationConfiguration: Password: "pass" RPC: Enabled: true + Addresses: + - ":30333" EnableCORSWorkaround: false MaxGasInvoke: 15 - Port: 30333 Prometheus: Enabled: true - Port: 20001 + Addresses: + - ":20001" Pprof: Enabled: false - Port: 20011 + Addresses: + - ":20011" UnlockWallet: Path: "/wallet1.json" Password: "one" diff --git a/config/protocol.privnet.docker.three.yml b/config/protocol.privnet.docker.three.yml index 7455b6932..3676981c6 100644 --- a/config/protocol.privnet.docker.three.yml +++ b/config/protocol.privnet.docker.three.yml @@ -69,15 +69,18 @@ ApplicationConfiguration: Password: "pass" RPC: Enabled: true + Addresses: + - ":30335" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 30335 Prometheus: Enabled: true - Port: 20003 + Addresses: + - ":20003" Pprof: Enabled: false - Port: 20013 + Addresses: + - ":20013" UnlockWallet: Path: "/wallet3.json" Password: "three" diff --git a/config/protocol.privnet.docker.two.yml b/config/protocol.privnet.docker.two.yml index ffc2ffaf3..c613de8f0 100644 --- a/config/protocol.privnet.docker.two.yml +++ b/config/protocol.privnet.docker.two.yml @@ -71,13 +71,16 @@ ApplicationConfiguration: Enabled: true MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 30334 + Addresses: + - ":30334" Prometheus: Enabled: true - Port: 20002 + Addresses: + - ":20002" Pprof: Enabled: false - Port: 20012 + Addresses: + - ":20012" UnlockWallet: Path: "/wallet2.json" Password: "two" diff --git a/config/protocol.privnet.yml b/config/protocol.privnet.yml index c4fe64fec..57e20a4ae 100644 --- a/config/protocol.privnet.yml +++ b/config/protocol.privnet.yml @@ -56,19 +56,23 @@ ApplicationConfiguration: Password: "pass" RPC: Enabled: true + Addresses: + - ":20331" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 20331 SessionEnabled: true SessionExpirationTime: 180 # higher expiration time for manual requests and tests. TLSConfig: Enabled: false - Port: 20330 + Addresses: + - ":20330" CertFile: serv.crt KeyFile: serv.key Prometheus: Enabled: true - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false - Port: 2113 + Addresses: + - ":2113" diff --git a/config/protocol.testnet.neofs.yml b/config/protocol.testnet.neofs.yml index 90a222897..6c52068dc 100644 --- a/config/protocol.testnet.neofs.yml +++ b/config/protocol.testnet.neofs.yml @@ -64,15 +64,17 @@ ApplicationConfiguration: - application/json RPC: Enabled: true + Addresses: + - ":50332" EnableCORSWorkaround: false MaxGasInvoke: 100 - Port: 50332 StartWhenSynchronized: false TLSConfig: Enabled: false + Addresses: + - ":50331" CertFile: server.crt KeyFile: server.key - Port: 50331 P2PNotary: Enabled: false UnlockWallet: @@ -80,7 +82,9 @@ ApplicationConfiguration: Path: "/notary_wallet.json" Prometheus: Enabled: false - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false - Port: 2113 + Addresses: + - ":2113" diff --git a/config/protocol.testnet.yml b/config/protocol.testnet.yml index 259bab32c..7b8378199 100644 --- a/config/protocol.testnet.yml +++ b/config/protocol.testnet.yml @@ -84,17 +84,21 @@ ApplicationConfiguration: Password: "pass" RPC: Enabled: true + Addresses: + - ":20332" MaxGasInvoke: 15 EnableCORSWorkaround: false - Port: 20332 TLSConfig: Enabled: false - Port: 20331 + Addresses: + - ":20331" CertFile: serv.crt KeyFile: serv.key Prometheus: Enabled: true - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false - Port: 2113 + Addresses: + - ":2113" diff --git a/config/protocol.unit_testnet.single.yml b/config/protocol.unit_testnet.single.yml index 0f53039c0..c97e28d59 100644 --- a/config/protocol.unit_testnet.single.yml +++ b/config/protocol.unit_testnet.single.yml @@ -53,14 +53,16 @@ ApplicationConfiguration: Path: "/notary_wallet.json" Password: "pass" RPC: - Address: localhost MaxGasInvoke: 15 Enabled: true + Addresses: + - "localhost:0" # let the system choose port dynamically EnableCORSWorkaround: false - Port: 0 # let the system choose port dynamically Prometheus: Enabled: false #since it's not useful for unit tests. - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false #since it's not useful for unit tests. - Port: 2113 + Addresses: + - ":2113" diff --git a/config/protocol.unit_testnet.yml b/config/protocol.unit_testnet.yml index 6b2eff506..cc3a19be3 100644 --- a/config/protocol.unit_testnet.yml +++ b/config/protocol.unit_testnet.yml @@ -59,16 +59,18 @@ ApplicationConfiguration: Path: "/notary_wallet.json" Password: "pass" RPC: - Address: localhost MaxGasInvoke: 15 Enabled: true + Addresses: + - "localhost:0" # let the system choose port dynamically EnableCORSWorkaround: false SessionEnabled: true SessionExpirationTime: 2 # enough for tests as they run locally. - Port: 0 # let the system choose port dynamically Prometheus: Enabled: false #since it's not useful for unit tests. - Port: 2112 + Addresses: + - ":2112" Pprof: Enabled: false #since it's not useful for unit tests. - Port: 2113 + Addresses: + - ":2113" diff --git a/docs/node-configuration.md b/docs/node-configuration.md index 9255fe76a..0dcde074a 100644 --- a/docs/node-configuration.md +++ b/docs/node-configuration.md @@ -118,17 +118,21 @@ Prometheus) and has the following structure: ``` Pprof: Enabled: false - Address: "" - Port: "30001" + Addresses: + - ":30001" Prometheus: Enabled: false - Address: "" - Port: "40001" + Addresses: + - ":40001" ``` where: - `Enabled` denotes whether the service is enabled. -- `Address` is a service address to be running at. -- `Port` is a service port to be bound to. +- `Address` is a service address to be running at. Warning: this field is deprecated, + please, use `Addresses` instead. +- `Port` is a service port to be bound to. Warning: this field is deprecated, please, + use `Addresses` instead. +- `Addresses` is a list of service addresses to be running at and listen to in + the form of "host:port". ### RPC Configuration @@ -137,29 +141,32 @@ the following structure: ``` RPC: Enabled: true - Address: "" + Addresses: + - ":10332" EnableCORSWorkaround: false MaxGasInvoke: 50 MaxIteratorResultItems: 100 MaxFindResultItems: 100 MaxNEP11Tokens: 100 MaxWebSocketClients: 64 - Port: 10332 SessionEnabled: false SessionExpirationTime: 15 SessionBackedByMPT: false SessionPoolSize: 20 StartWhenSynchronized: false TLSConfig: - Address: "" + Addresses: + - ":10331" CertFile: serv.crt Enabled: true - Port: 10331 KeyFile: serv.key ``` where: - `Enabled` denotes whether an RPC server should be started. -- `Address` is an RPC server address to be running at. +- `Address` is an RPC server address to be running at. Warning: this field is + deprecated, please, use `Addresses` instead. +- `Addresses` is a list of RPC server addresses to be running at and listen to in + the form of "host:port". - `EnableCORSWorkaround` turns on a set of origin-related behaviors that make RPC server wide open for connections from any origins. It enables OPTIONS request handling for pre-flight CORS and makes the server send @@ -182,7 +189,8 @@ where: number (64 by default). Attempts to establish additional connections will lead to websocket handshake failures. Use "-1" to disable websocket connections (0 will lead to using the default value). -- `Port` is an RPC server port it should be bound to. +- `Port` is an RPC server port it should be bound to. Warning: this field is + deprecated, please, use `Addresses` instead. - `SessionEnabled` denotes whether session-based iterator JSON-RPC API is enabled. If true, then all iterators got from `invoke*` calls will be stored as sessions on the server side available for further traverse. `traverseiterator` and diff --git a/internal/testcli/executor.go b/internal/testcli/executor.go index c8f731d18..5b55d553c 100644 --- a/internal/testcli/executor.go +++ b/internal/testcli/executor.go @@ -348,7 +348,7 @@ func DeployContract(t *testing.T, e *Executor, inPath, configPath, wallet, addre "--out", nefName, "--manifest", manifestName) e.In.WriteString(pass + "\r") e.Run(t, "neo-go", "contract", "deploy", - "--rpc-endpoint", "http://"+e.RPC.Addr, + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--wallet", wallet, "--address", address, "--force", "--in", nefName, "--manifest", manifestName) diff --git a/pkg/config/application_config_test.go b/pkg/config/application_config_test.go index a675ae65b..8b5428e8f 100644 --- a/pkg/config/application_config_test.go +++ b/pkg/config/application_config_test.go @@ -20,12 +20,3 @@ func TestApplicationConfigurationEquals(t *testing.T) { require.NoError(t, err) require.False(t, cfg1.ApplicationConfiguration.EqualsButServices(&cfg2.ApplicationConfiguration)) } - -// TestApplicationConfiguration_UnmarshalRPCBasicService is aimed to check that BasicService -// config of RPC service can be properly unmarshalled. -func TestApplicationConfiguration_UnmarshalRPCBasicService(t *testing.T) { - cfg, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml")) - require.NoError(t, err) - require.True(t, cfg.ApplicationConfiguration.RPC.Enabled) - require.Equal(t, uint16(10332), cfg.ApplicationConfiguration.RPC.Port) -} diff --git a/pkg/config/basic_service.go b/pkg/config/basic_service.go index 71840ed36..50014b06b 100644 --- a/pkg/config/basic_service.go +++ b/pkg/config/basic_service.go @@ -8,12 +8,32 @@ import ( // BasicService is used as a simple base for node services like Pprof, RPC or // Prometheus monitoring. type BasicService struct { - Enabled bool `yaml:"Enabled"` - Address string `yaml:"Address"` - Port uint16 `yaml:"Port"` + Enabled bool `yaml:"Enabled"` + // Deprecated: please, use Addresses section instead. This field will be removed later. + Address *string `yaml:"Address,omitempty"` + // Deprecated: please, use Addresses section instead. This field will be removed later. + Port *uint16 `yaml:"Port,omitempty"` + // Addresses holds the list of bind addresses in the form of "address:port". + Addresses []string `yaml:"Addresses"` } -// FormatAddress returns the full service's address in the form of "address:port". -func (s BasicService) FormatAddress() string { - return net.JoinHostPort(s.Address, strconv.FormatUint(uint64(s.Port), 10)) +// GetAddresses returns the set of unique (in terms of raw strings) pairs host:port +// for the given basic service. +func (s BasicService) GetAddresses() []string { + addrs := make([]string, len(s.Addresses), len(s.Addresses)+1) + copy(addrs, s.Addresses) + if s.Address != nil || s.Port != nil { //nolint:staticcheck // SA1019: s.Address is deprecated + var ( + addr string + port uint16 + ) + if s.Address != nil { //nolint:staticcheck // SA1019: s.Address is deprecated + addr = *s.Address //nolint:staticcheck // SA1019: s.Address is deprecated + } + if s.Port != nil { //nolint:staticcheck // SA1019: s.Port is deprecated + port = *s.Port //nolint:staticcheck // SA1019: s.Port is deprecated + } + addrs = append(addrs, net.JoinHostPort(addr, strconv.FormatUint(uint64(port), 10))) + } + return addrs } diff --git a/pkg/config/basic_service_test.go b/pkg/config/basic_service_test.go index 7661bca69..685ddd9da 100644 --- a/pkg/config/basic_service_test.go +++ b/pkg/config/basic_service_test.go @@ -6,14 +6,24 @@ import ( "github.com/stretchr/testify/require" ) -func TestBasicService_FormatAddress(t *testing.T) { - for expected, tc := range map[string]BasicService{ - "localhost:10332": {Address: "localhost", Port: 10332}, - "127.0.0.1:0": {Address: "127.0.0.1"}, - ":0": {}, - } { - t.Run(expected, func(t *testing.T) { - require.Equal(t, expected, tc.FormatAddress()) - }) +func TestBasicService_GetAddresses(t *testing.T) { + addr := "1.2.3.4" + port := uint16(1234) + s := BasicService{ + Enabled: false, + Address: &addr, + Port: &port, + Addresses: []string{"1.2.3.4:1234", /* same as Address:Port */ + "3.4.5.6:1234", "2.3.4.5", ":1235", "2.3.4.5:1234", + "3.4.5.6:1234" /* already in list */}, } + require.Equal(t, []string{ + "1.2.3.4:1234", + "3.4.5.6:1234", + "2.3.4.5", + ":1235", + "2.3.4.5:1234", + "3.4.5.6:1234", + "1.2.3.4:1234", + }, s.GetAddresses()) } diff --git a/pkg/config/rpc_config_test.go b/pkg/config/rpc_config_test.go new file mode 100644 index 000000000..2d9a02dcf --- /dev/null +++ b/pkg/config/rpc_config_test.go @@ -0,0 +1,24 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +// TestRPC_UnmarshalBasicService is aimed to check that BasicService config of +// RPC service can be properly unmarshalled. This test may be removed after +// Address and Port config fields removal. +func TestRPC_UnmarshalBasicService(t *testing.T) { + data := ` +Enabled: true +Port: 10332 +MaxGasInvoke: 15 +` + cfg := &RPC{} + err := yaml.Unmarshal([]byte(data), &cfg) + require.NoError(t, err) + require.True(t, cfg.Enabled) + require.Equal(t, uint16(10332), *cfg.Port) +} diff --git a/pkg/services/metrics/metrics.go b/pkg/services/metrics/metrics.go index b7af0c3a9..e814e1eff 100644 --- a/pkg/services/metrics/metrics.go +++ b/pkg/services/metrics/metrics.go @@ -3,31 +3,62 @@ package metrics import ( "context" "errors" + "fmt" + "net" "net/http" "github.com/nspcc-dev/neo-go/pkg/config" + "go.uber.org/atomic" "go.uber.org/zap" ) // Service serves metrics. type Service struct { - *http.Server + http []*http.Server config config.BasicService log *zap.Logger serviceType string + started *atomic.Bool +} + +// NewService configures logger and returns new service instance. +func NewService(name string, httpServers []*http.Server, cfg config.BasicService, log *zap.Logger) *Service { + return &Service{ + http: httpServers, + config: cfg, + serviceType: name, + log: log.With(zap.String("service", name)), + started: atomic.NewBool(false), + } } // Start runs http service with the exposed endpoint on the configured port. -func (ms *Service) Start() { +func (ms *Service) Start() error { if ms.config.Enabled { - ms.log.Info("service is running", zap.String("endpoint", ms.Addr)) - err := ms.ListenAndServe() - if err != nil && !errors.Is(err, http.ErrServerClosed) { - ms.log.Warn("service couldn't start on configured port") + if !ms.started.CAS(false, true) { + ms.log.Info("service already started") + return nil + } + for _, srv := range ms.http { + ms.log.Info("starting service", zap.String("endpoint", srv.Addr)) + + ln, err := net.Listen("tcp", srv.Addr) + if err != nil { + return fmt.Errorf("failed to listen on %s: %w", srv.Addr, err) + } + srv.Addr = ln.Addr().String() // set Addr to the actual address + + go func(s *http.Server) { + err = s.Serve(ln) + if !errors.Is(err, http.ErrServerClosed) { + ms.log.Error("failed to start service", zap.String("endpoint", s.Addr), zap.Error(err)) + } + }(srv) } } else { ms.log.Info("service hasn't started since it's disabled") } + return nil } // ShutDown stops the service. @@ -35,9 +66,14 @@ func (ms *Service) ShutDown() { if !ms.config.Enabled { return } - ms.log.Info("shutting down service", zap.String("endpoint", ms.Addr)) - err := ms.Shutdown(context.Background()) - if err != nil { - ms.log.Error("can't shut service down", zap.Error(err)) + if !ms.started.CAS(true, false) { + return + } + for _, srv := range ms.http { + ms.log.Info("shutting down service", zap.String("endpoint", srv.Addr)) + err := srv.Shutdown(context.Background()) + if err != nil { + ms.log.Error("can't shut service down", zap.String("endpoint", srv.Addr), zap.Error(err)) + } } } diff --git a/pkg/services/metrics/pprof.go b/pkg/services/metrics/pprof.go index 343982bdc..9dc1f7d63 100644 --- a/pkg/services/metrics/pprof.go +++ b/pkg/services/metrics/pprof.go @@ -24,13 +24,13 @@ func NewPprofService(cfg config.BasicService, log *zap.Logger) *Service { handler.HandleFunc("/debug/pprof/symbol", pprof.Symbol) handler.HandleFunc("/debug/pprof/trace", pprof.Trace) - return &Service{ - Server: &http.Server{ - Addr: cfg.FormatAddress(), + addrs := cfg.GetAddresses() + srvs := make([]*http.Server, len(addrs)) + for i, addr := range addrs { + srvs[i] = &http.Server{ + Addr: addr, Handler: handler, - }, - config: cfg, - serviceType: "Pprof", - log: log.With(zap.String("service", "Pprof")), + } } + return NewService("Pprof", srvs, cfg, log) } diff --git a/pkg/services/metrics/prometheus.go b/pkg/services/metrics/prometheus.go index 209c13d7c..854fd37f4 100644 --- a/pkg/services/metrics/prometheus.go +++ b/pkg/services/metrics/prometheus.go @@ -17,13 +17,13 @@ func NewPrometheusService(cfg config.BasicService, log *zap.Logger) *Service { return nil } - return &Service{ - Server: &http.Server{ - Addr: cfg.FormatAddress(), - Handler: promhttp.Handler(), - }, - config: cfg, - serviceType: "Prometheus", - log: log.With(zap.String("service", "Prometheus")), + addrs := cfg.GetAddresses() + srvs := make([]*http.Server, len(addrs)) + for i, addr := range addrs { + srvs[i] = &http.Server{ + Addr: addr, + Handler: promhttp.Handler(), // share metrics between multiple prometheus handlers + } } + return NewService("Prometheus", srvs, cfg, log) } diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go index 98af82b01..880c3c154 100644 --- a/pkg/services/rpcsrv/server.go +++ b/pkg/services/rpcsrv/server.go @@ -117,7 +117,9 @@ type ( // Server represents the JSON-RPC 2.0 server. Server struct { - *http.Server + http []*http.Server + https []*http.Server + chain Ledger config config.RPC // wsReadLimit represents web-socket message limit for a receiving side. @@ -128,7 +130,6 @@ type ( coreServer *network.Server oracle *atomic.Value log *zap.Logger - https *http.Server shutdown chan struct{} started *atomic.Bool errChan chan error @@ -254,14 +255,22 @@ var invalidBlockHeightError = func(index int, height int) *neorpc.Error { // New creates a new Server struct. func New(chain Ledger, conf config.RPC, coreServer *network.Server, orc OracleHandler, log *zap.Logger, errChan chan error) Server { - httpServer := &http.Server{ - Addr: conf.FormatAddress(), + addrs := conf.GetAddresses() + httpServers := make([]*http.Server, len(addrs)) + for i, addr := range addrs { + httpServers[i] = &http.Server{ + Addr: addr, + } } - var tlsServer *http.Server + var tlsServers []*http.Server if cfg := conf.TLSConfig; cfg.Enabled { - tlsServer = &http.Server{ - Addr: cfg.FormatAddress(), + addrs := cfg.GetAddresses() + tlsServers = make([]*http.Server, len(addrs)) + for i, addr := range addrs { + tlsServers[i] = &http.Server{ + Addr: addr, + } } } @@ -289,7 +298,9 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server, wsOriginChecker = func(_ *http.Request) bool { return true } } return Server{ - Server: httpServer, + http: httpServers, + https: tlsServers, + chain: chain, config: conf, wsReadLimit: int64(protoCfg.MaxBlockSize*4)/3 + 1024, // Enough for Base64-encoded content of `submitblock` and `submitp2pnotaryrequest`. @@ -299,7 +310,6 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server, coreServer: coreServer, log: log, oracle: oracleWrapped, - https: tlsServer, shutdown: make(chan struct{}), started: atomic.NewBool(false), errChan: errChan, @@ -333,40 +343,48 @@ func (s *Server) Start() { s.log.Info("RPC server already started") return } - s.Handler = http.HandlerFunc(s.handleHTTPRequest) - s.log.Info("starting rpc-server", zap.String("endpoint", s.Addr)) + for _, srv := range s.http { + srv.Handler = http.HandlerFunc(s.handleHTTPRequest) + s.log.Info("starting rpc-server", zap.String("endpoint", srv.Addr)) + + ln, err := net.Listen("tcp", srv.Addr) + if err != nil { + s.errChan <- fmt.Errorf("failed to listen on %s: %w", srv.Addr, err) + return + } + srv.Addr = ln.Addr().String() // set Addr to the actual address + go func(server *http.Server) { + err = server.Serve(ln) + if !errors.Is(err, http.ErrServerClosed) { + s.log.Error("failed to start RPC server", zap.Error(err)) + s.errChan <- err + } + }(srv) + } go s.handleSubEvents() if cfg := s.config.TLSConfig; cfg.Enabled { - s.https.Handler = http.HandlerFunc(s.handleHTTPRequest) - s.log.Info("starting rpc-server (https)", zap.String("endpoint", s.https.Addr)) - go func() { - ln, err := net.Listen("tcp", s.https.Addr) + for _, srv := range s.https { + srv.Handler = http.HandlerFunc(s.handleHTTPRequest) + s.log.Info("starting rpc-server (https)", zap.String("endpoint", srv.Addr)) + + ln, err := net.Listen("tcp", srv.Addr) if err != nil { s.errChan <- err return } - s.https.Addr = ln.Addr().String() - err = s.https.ServeTLS(ln, cfg.CertFile, cfg.KeyFile) - if !errors.Is(err, http.ErrServerClosed) { - s.log.Error("failed to start TLS RPC server", zap.Error(err)) - s.errChan <- err - } - }() - } - ln, err := net.Listen("tcp", s.Addr) - if err != nil { - s.errChan <- err - return - } - s.Addr = ln.Addr().String() // set Addr to the actual address - go func() { - err = s.Serve(ln) - if !errors.Is(err, http.ErrServerClosed) { - s.log.Error("failed to start RPC server", zap.Error(err)) - s.errChan <- err + srv.Addr = ln.Addr().String() + + go func(srv *http.Server) { + err = srv.ServeTLS(ln, cfg.CertFile, cfg.KeyFile) + if !errors.Is(err, http.ErrServerClosed) { + s.log.Error("failed to start TLS RPC server", + zap.String("endpoint", srv.Addr), zap.Error(err)) + s.errChan <- err + } + }(srv) } - }() + } } // Shutdown stops the RPC server if it's running. It can only be called once, @@ -381,17 +399,23 @@ func (s *Server) Shutdown() { close(s.shutdown) if s.config.TLSConfig.Enabled { - s.log.Info("shutting down RPC server (https)", zap.String("endpoint", s.https.Addr)) - err := s.https.Shutdown(context.Background()) - if err != nil { - s.log.Warn("error during RPC (https) server shutdown", zap.Error(err)) + for _, srv := range s.https { + s.log.Info("shutting down RPC server (https)", zap.String("endpoint", srv.Addr)) + err := srv.Shutdown(context.Background()) + if err != nil { + s.log.Warn("error during RPC (https) server shutdown", + zap.String("endpoint", srv.Addr), zap.Error(err)) + } } } - s.log.Info("shutting down RPC server", zap.String("endpoint", s.Addr)) - err := s.Server.Shutdown(context.Background()) - if err != nil { - s.log.Warn("error during RPC (http) server shutdown", zap.Error(err)) + for _, srv := range s.http { + s.log.Info("shutting down RPC server", zap.String("endpoint", srv.Addr)) + err := srv.Shutdown(context.Background()) + if err != nil { + s.log.Warn("error during RPC (http) server shutdown", + zap.String("endpoint", srv.Addr), zap.Error(err)) + } } // Perform sessions finalisation. @@ -2790,3 +2814,13 @@ func escapeForLog(in string) string { return c }, in) } + +// Addresses returns the list of addresses RPC server is listening to in the form of +// address:port. +func (s *Server) Addresses() []string { + res := make([]string, len(s.http)) + for i, srv := range s.http { + res[i] = srv.Addr + } + return res +}