diff --git a/cmd/neofs-node/config.go b/cmd/neofs-node/config.go index 69519fdee..990c1a27a 100644 --- a/cmd/neofs-node/config.go +++ b/cmd/neofs-node/config.go @@ -139,6 +139,8 @@ type cfgMorph struct { blockTimers []*timer.BlockTimer // all combined timers eigenTrustTimer *timer.BlockTimer // timer for EigenTrust iterations + + proxyScriptHash neogoutil.Uint160 } type cfgAccounting struct { @@ -278,6 +280,9 @@ func initCfg(path string) *cfg { maxChunkSize: maxChunkSize, maxAddrAmount: maxAddrAmount, }, + cfgMorph: cfgMorph{ + proxyScriptHash: contractsconfig.Proxy(appCfg), + }, localAddr: netAddr, respSvc: response.NewService( response.WithNetworkState(netState), diff --git a/cmd/neofs-node/config/contracts/config.go b/cmd/neofs-node/config/contracts/config.go index 882747342..ac0d5bbf8 100644 --- a/cmd/neofs-node/config/contracts/config.go +++ b/cmd/neofs-node/config/contracts/config.go @@ -14,6 +14,7 @@ const ( // Netmap returns value of "netmap" config parameter // from "contracts" section. // +// Returns zero filled script hash if value is not set. // Throws panic if value is not a 20-byte LE hex-encoded string. func Netmap(c *config.Config) util.Uint160 { return contractAddress(c, "netmap") @@ -22,6 +23,7 @@ func Netmap(c *config.Config) util.Uint160 { // Balance returns value of "balance" config parameter // from "contracts" section. // +// Returns zero filled script hash if value is not set. // Throws panic if value is not a 20-byte LE hex-encoded string. func Balance(c *config.Config) util.Uint160 { return contractAddress(c, "balance") @@ -30,6 +32,7 @@ func Balance(c *config.Config) util.Uint160 { // Container returns value of "container" config parameter // from "contracts" section. // +// Returns zero filled script hash if value is not set. // Throws panic if value is not a 20-byte LE hex-encoded string. func Container(c *config.Config) util.Uint160 { return contractAddress(c, "container") @@ -38,6 +41,7 @@ func Container(c *config.Config) util.Uint160 { // Reputation returns value of "reputation" config parameter // from "contracts" section. // +// Returns zero filled script hash if value is not set. // Throws panic if value is not a 20-byte LE hex-encoded string. func Reputation(c *config.Config) util.Uint160 { return contractAddress(c, "reputation") @@ -46,6 +50,7 @@ func Reputation(c *config.Config) util.Uint160 { // Proxy returns value of "proxy" config parameter // from "contracts" section. // +// Returns zero filled script hash if value is not set. // Throws panic if value is not a 20-byte LE hex-encoded string. func Proxy(c *config.Config) util.Uint160 { return contractAddress(c, "proxy") @@ -54,11 +59,7 @@ func Proxy(c *config.Config) util.Uint160 { func contractAddress(c *config.Config, name string) util.Uint160 { v := config.String(c.Sub(subsection), name) if v == "" { - panic(fmt.Errorf( - "empty %s contract address, see `contracts.%s` section", - name, - name, - )) + return util.Uint160{} // if address is not set, then NNS resolver should be used } addr, err := util.Uint160DecodeStringLE(v) diff --git a/cmd/neofs-node/config/contracts/config_test.go b/cmd/neofs-node/config/contracts/config_test.go index 53184d676..673fe519d 100644 --- a/cmd/neofs-node/config/contracts/config_test.go +++ b/cmd/neofs-node/config/contracts/config_test.go @@ -13,11 +13,13 @@ import ( func TestContractsSection(t *testing.T) { t.Run("defaults", func(t *testing.T) { empty := configtest.EmptyConfig() + emptyHash := util.Uint160{} - require.Panics(t, func() { contractsconfig.Balance(empty) }) - require.Panics(t, func() { contractsconfig.Container(empty) }) - require.Panics(t, func() { contractsconfig.Netmap(empty) }) - require.Panics(t, func() { contractsconfig.Reputation(empty) }) + require.Equal(t, emptyHash, contractsconfig.Balance(empty)) + require.Equal(t, emptyHash, contractsconfig.Container(empty)) + require.Equal(t, emptyHash, contractsconfig.Netmap(empty)) + require.Equal(t, emptyHash, contractsconfig.Reputation(empty)) + require.Equal(t, emptyHash, contractsconfig.Proxy(empty)) }) const path = "../../../../config/example/node" diff --git a/cmd/neofs-node/morph.go b/cmd/neofs-node/morph.go index f9067012d..dea712a9b 100644 --- a/cmd/neofs-node/morph.go +++ b/cmd/neofs-node/morph.go @@ -8,7 +8,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/util" - contractsconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/contracts" mainchainconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/mainchain" morphconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/morph" "github.com/nspcc-dev/neofs-node/pkg/core/netmap" @@ -77,10 +76,12 @@ func initMorphComponents(c *cfg) { c.cfgMorph.notaryEnabled = cli.ProbeNotary() + lookupScriptHashesInNNS(c) // smart contract auto negotiation + if c.cfgMorph.notaryEnabled { err = c.cfgMorph.client.EnableNotarySupport( client.WithProxyContract( - contractsconfig.Proxy(c.appCfg), + c.cfgMorph.proxyScriptHash, ), ) fatalOnErr(err) @@ -264,3 +265,30 @@ func registerNotificationHandlers(scHash util.Uint160, lis event.Listener, parse func registerBlockHandler(lis event.Listener, handler event.BlockHandler) { lis.RegisterBlockHandler(handler) } + +// lookupScriptHashesInNNS looks up for contract script hashes in NNS contract of side +// chain if they were not specified in config file. +func lookupScriptHashesInNNS(c *cfg) { + var ( + err error + + emptyHash = util.Uint160{} + targets = [...]struct { + h *util.Uint160 + nnsName string + }{ + {&c.cfgNetmap.scriptHash, client.NNSNetmapContractName}, + {&c.cfgAccounting.scriptHash, client.NNSBalanceContractName}, + {&c.cfgContainer.scriptHash, client.NNSContainerContractName}, + {&c.cfgReputation.scriptHash, client.NNSReputationContractName}, + {&c.cfgMorph.proxyScriptHash, client.NNSProxyContractName}, + } + ) + + for _, t := range targets { + if emptyHash.Equals(*t.h) { + *t.h, err = c.cfgMorph.client.NNSContractAddress(t.nnsName) + fatalOnErrDetails(fmt.Sprintf("can't resolve %s in NNS", t.nnsName), err) + } + } +}