diff --git a/CHANGELOG.md b/CHANGELOG.md index d8b75d4fee..2ef3c81b46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,26 @@ Changelog for NeoFS Node ### Fixed ### Changed +- Move `fschain_autodeploy` into `fschain.disable_autodeploy` in IR config (#3619) +- Move `without_mainnet` into `mainnet.enabled` in IR config (#3619) +- Move `governance.disable` into `mainnet.disable_governance_sync` in IR config (#3619) +- Move `fee.main_chain` into `mainnet.extra_fee` in IR config (#3619) +- Move `contracts` into `mainnet.contracts` in IR config (#3619) ### Removed ### Updated ### Updating from v0.49.0 +Use IR configuration options: +- `fschain.disable_autodeploy` instead of deprecated `fschain_autodeploy` with reverted value, +by default autodeploy is enabled now; +- `mainnet.enabled` instead of deprecated `without_mainnet` with reverted value, +by default mainnet is disabled now; +- `mainnet.disable_governance_sync` instead of deprecated `governance.disable`; +- `mainnet.extra_fee` instead of deprecated `fee.main_chain`; +- `mainnet.contracts` instead of deprecated `contracts`; +Old options are still supported but will be removed in future releases. ## [0.49.0] - 2025-10-06 - Dochodo diff --git a/cmd/neofs-ir/defaults.go b/cmd/neofs-ir/defaults.go index bacbf868cc..5c08ab5597 100644 --- a/cmd/neofs-ir/defaults.go +++ b/cmd/neofs-ir/defaults.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-node/internal/configutil" irconfig "github.com/nspcc-dev/neofs-node/pkg/innerring/config" "github.com/spf13/viper" @@ -22,8 +23,6 @@ func newConfig(path string) (*irconfig.Config, error) { v.AutomaticEnv() v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - defaultConfiguration(v) - if path != "" { v.SetConfigFile(path) if strings.HasSuffix(path, ".json") { @@ -43,61 +42,115 @@ func newConfig(path string) (*irconfig.Config, error) { return nil, fmt.Errorf("unable to decode config: %w", err) } + applyDefaults(&cfg) + return &cfg, nil } -func defaultConfiguration(cfg *viper.Viper) { - cfg.SetDefault("logger.level", "info") - cfg.SetDefault("logger.encoding", "console") - - cfg.SetDefault("pprof.address", "localhost:6060") - cfg.SetDefault("pprof.shutdown_timeout", "30s") - - cfg.SetDefault("prometheus.address", "localhost:9090") - cfg.SetDefault("prometheus.shutdown_timeout", "30s") - - cfg.SetDefault("without_mainnet", false) - - cfg.SetDefault("node.persistent_state.path", ".neofs-ir-state") - - cfg.SetDefault("fschain.dial_timeout", time.Minute) - cfg.SetDefault("fschain.reconnections_number", 5) - cfg.SetDefault("fschain.reconnections_delay", 5*time.Second) - cfg.SetDefault("fschain.validators", []string{}) +func applyDefaults(cfg *irconfig.Config) { + // Logger defaults + if cfg.Logger.Level == "" { + cfg.Logger.Level = "info" + } + if cfg.Logger.Encoding == "" { + cfg.Logger.Encoding = "console" + } - cfg.SetDefault("mainnet.dial_timeout", time.Minute) - cfg.SetDefault("mainnet.reconnections_number", 5) - cfg.SetDefault("mainnet.reconnections_delay", 5*time.Second) + // Pprof defaults + if cfg.Pprof.Address == "" { + cfg.Pprof.Address = "localhost:6060" + } + if cfg.Pprof.ShutdownTimeout == 0 { + cfg.Pprof.ShutdownTimeout = 30 * time.Second + } - cfg.SetDefault("wallet.path", "") // inner ring node NEP-6 wallet - cfg.SetDefault("wallet.address", "") // account address - cfg.SetDefault("wallet.password", "") // password + // Prometheus defaults + if cfg.Prometheus.Address == "" { + cfg.Prometheus.Address = "localhost:9090" + } + if cfg.Prometheus.ShutdownTimeout == 0 { + cfg.Prometheus.ShutdownTimeout = 30 * time.Second + } - cfg.SetDefault("timers.collect_basic_income.mul", 1) - cfg.SetDefault("timers.collect_basic_income.div", 2) + // Node defaults + if cfg.Node.PersistentState.Path == "" { + cfg.Node.PersistentState.Path = ".neofs-ir-state" + } - cfg.SetDefault("workers.netmap", "10") - cfg.SetDefault("workers.balance", "10") - cfg.SetDefault("workers.neofs", "10") - cfg.SetDefault("workers.container", "10") - cfg.SetDefault("workers.alphabet", "10") - cfg.SetDefault("workers.reputation", "10") + // FSChain defaults + if cfg.FSChain.DialTimeout == 0 { + cfg.FSChain.DialTimeout = time.Minute + } + if cfg.FSChain.ReconnectionsNumber == 0 { + cfg.FSChain.ReconnectionsNumber = 5 + } + if cfg.FSChain.ReconnectionsDelay == 0 { + cfg.FSChain.ReconnectionsDelay = 5 * time.Second + } + if cfg.FSChain.Validators == nil { + cfg.FSChain.Validators = keys.PublicKeys{} + } - cfg.SetDefault("emit.storage.amount", 0) - cfg.SetDefault("emit.mint.cache_size", 1000) - cfg.SetDefault("emit.mint.threshold", 1) - cfg.SetDefault("emit.mint.value", 20000000) // 0.2 Fixed8 - cfg.SetDefault("emit.gas.balance_threshold", 0) + // Mainnet defaults + if cfg.Mainnet.ExtraFee == 0 { + cfg.Mainnet.ExtraFee = 5000_0000 // 0.5 Fixed8 + } + if cfg.Mainnet.DialTimeout == 0 { + cfg.Mainnet.DialTimeout = time.Minute + } + if cfg.Mainnet.ReconnectionsNumber == 0 { + cfg.Mainnet.ReconnectionsNumber = 5 + } + if cfg.Mainnet.ReconnectionsDelay == 0 { + cfg.Mainnet.ReconnectionsDelay = 5 * time.Second + } - cfg.SetDefault("settlement.basic_income_rate", 0) + // Timers defaults + if cfg.Timers.CollectBasicIncome.Mul == 0 { + cfg.Timers.CollectBasicIncome.Mul = 1 + } + if cfg.Timers.CollectBasicIncome.Div == 0 { + cfg.Timers.CollectBasicIncome.Div = 2 + } - cfg.SetDefault("indexer.cache_timeout", 15*time.Second) + // Workers defaults + if cfg.Workers.Netmap == 0 { + cfg.Workers.Netmap = 10 + } + if cfg.Workers.Balance == 0 { + cfg.Workers.Balance = 10 + } + if cfg.Workers.NeoFS == 0 { + cfg.Workers.NeoFS = 10 + } + if cfg.Workers.Container == 0 { + cfg.Workers.Container = 10 + } + if cfg.Workers.Alphabet == 0 { + cfg.Workers.Alphabet = 10 + } + if cfg.Workers.Reputation == 0 { + cfg.Workers.Reputation = 10 + } - // extra fee values for working mode without notary contract - cfg.SetDefault("fee.main_chain", 5000_0000) // 0.5 Fixed8 + // Emit defaults + if cfg.Emit.Mint.CacheSize == 0 { + cfg.Emit.Mint.CacheSize = 1000 + } + if cfg.Emit.Mint.Threshold == 0 { + cfg.Emit.Mint.Threshold = 1 + } + if cfg.Emit.Mint.Value == 0 { + cfg.Emit.Mint.Value = 20000000 // 0.2 Fixed8 + } - cfg.SetDefault("control.authorized_keys", []string{}) - cfg.SetDefault("control.grpc.endpoint", "") + // Indexer defaults + if cfg.Indexer.CacheTimeout == 0 { + cfg.Indexer.CacheTimeout = 15 * time.Second + } - cfg.SetDefault("governance.disable", false) + // Control defaults + if cfg.Control.AuthorizedKeys == nil { + cfg.Control.AuthorizedKeys = keys.PublicKeys{} + } } diff --git a/cmd/neofs-ir/defaults_test.go b/cmd/neofs-ir/defaults_test.go index 6c06d63fd2..6ee74c47d1 100644 --- a/cmd/neofs-ir/defaults_test.go +++ b/cmd/neofs-ir/defaults_test.go @@ -26,14 +26,23 @@ func TestValidateDefaultConfig(t *testing.T) { ReconnectionsNumber: 5, ReconnectionsDelay: 5000000000, }, - Validators: keys.PublicKeys{}, + DisableAutodeploy: false, + Validators: keys.PublicKeys{}, }, - FSChainAutodeploy: false, - NNS: config.NNS{SystemEmail: ""}, - Mainnet: config.BasicChain{ - DialTimeout: 60000000000, - ReconnectionsNumber: 5, - ReconnectionsDelay: 5000000000, + NNS: config.NNS{SystemEmail: ""}, + Mainnet: config.Mainnet{ + Enabled: false, + DisableGovernanceSync: false, + ExtraFee: 50000000, + Contracts: config.Contracts{ + NeoFS: "", + Processing: "", + }, + BasicChain: config.BasicChain{ + DialTimeout: 60000000000, + ReconnectionsNumber: 5, + ReconnectionsDelay: 5000000000, + }, }, Control: config.Control{ AuthorizedKeys: keys.PublicKeys{}, @@ -45,7 +54,6 @@ func TestValidateDefaultConfig(t *testing.T) { Path: ".neofs-ir-state", }, }, - Fee: config.Fee{MainChain: 50000000}, Timers: config.Timers{ CollectBasicIncome: config.BasicTimer{Mul: 1, Div: 2}, }, diff --git a/cmd/neofs-ir/validate_test.go b/cmd/neofs-ir/validate_test.go index 98d24b9b1d..f92742d2a5 100644 --- a/cmd/neofs-ir/validate_test.go +++ b/cmd/neofs-ir/validate_test.go @@ -192,7 +192,8 @@ func TestCheckForUnknownFieldsExample(t *testing.T) { "wss://sidechain2.fs.neo.org:30333/ws", }, }, - Validators: validators, + DisableAutodeploy: true, + Validators: validators, Consensus: config.Consensus{ Magic: 15405, Committee: committee, @@ -248,17 +249,25 @@ func TestCheckForUnknownFieldsExample(t *testing.T) { RemoveUntraceableBlocks: false, P2PNotaryRequestPayloadPoolSize: 100, }}, - FSChainAutodeploy: true, NNS: config.NNS{ SystemEmail: "usr@domain.io", }, - Mainnet: config.BasicChain{ - DialTimeout: time.Minute, - ReconnectionsNumber: 5, - ReconnectionsDelay: 5 * time.Second, - Endpoints: []string{ - "wss://mainchain1.fs.neo.org:30333/ws", - "wss://mainchain.fs.neo.org:30333/ws", + Mainnet: config.Mainnet{ + Enabled: false, + DisableGovernanceSync: false, + ExtraFee: 50000000, + Contracts: config.Contracts{ + NeoFS: "ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62", + Processing: "597f5894867113a41e192801709c02497f611de8", + }, + BasicChain: config.BasicChain{ + DialTimeout: time.Minute, + ReconnectionsNumber: 5, + ReconnectionsDelay: 5 * time.Second, + Endpoints: []string{ + "wss://mainchain1.fs.neo.org:30333/ws", + "wss://mainchain.fs.neo.org:30333/ws", + }, }, }, Control: config.Control{ diff --git a/config/example/ir.env b/config/example/ir.env index 091395adb1..48bbae5b5c 100644 --- a/config/example/ir.env +++ b/config/example/ir.env @@ -8,12 +8,18 @@ NEOFS_IR_WALLET_PASSWORD=secret NEOFS_IR_WITHOUT_MAINNET=false +NEOFS_IR_FSCHAIN_DISABLE_AUTODEPLOY=true NEOFS_IR_FSCHAIN_DIAL_TIMEOUT=1m NEOFS_IR_FSCHAIN_RECONNECTIONS_NUMBER=5 NEOFS_IR_FSCHAIN_RECONNECTIONS_DELAY=5s NEOFS_IR_FSCHAIN_ENDPOINTS="wss://sidechain1.fs.neo.org:30333/ws wss://sidechain2.fs.neo.org:30333/ws" NEOFS_IR_FSCHAIN_VALIDATORS="0283120f4c8c1fc1d792af5063d2def9da5fddc90bc1384de7fcfdda33c3860170" +NEOFS_IR_MAINNET_ENABLED=false +NEOFS_IR_MAINNET_DISABLE_GOVERNANCE_SYNC=false +NEOFS_IR_MAINNET_EXTRA_FEE=50000000 +NEOFS_IR_MAINNET_CONTRACTS_NEOFS=ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62 +NEOFS_IR_MAINNET_CONTRACTS_PROCESSING=597f5894867113a41e192801709c02497f611de8MAINNET_ NEOFS_IR_MAINNET_DIAL_TIMEOUT=1m NEOFS_IR_MAINNET_RECONNECTIONS_NUMBER=5 NEOFS_IR_MAINNET_RECONNECTIONS_DELAY=5s diff --git a/config/example/ir.yaml b/config/example/ir.yaml index 99d7191da2..e2ac741786 100644 --- a/config/example/ir.yaml +++ b/config/example/ir.yaml @@ -16,6 +16,7 @@ wallet: without_mainnet: false # Run application in single chain environment without mainchain fschain: + disable_autodeploy: true # Optional flag to disable auto-deployment procedure of the FS chain; defaults to 'false' dial_timeout: 1m # Timeout for RPC client connection to sidechain reconnections_number: 5 # number of reconnection attempts reconnections_delay: 5s # time delay b/w reconnection attempts @@ -109,8 +110,7 @@ fschain: p2p_notary_request_payload_pool_size: 100 # Optional size of the node's P2P Notary request payloads memory pool. # Defaults to 1000. Must be unsigned integer in range [1:2147483647]. -fschain_autodeploy: true # Optional flag to run auto-deployment procedure of the FS chain. By default, - # the chain is expected to be deployed/updated in the background (e.g. via NeoFS ADM tool). +fschain_autodeploy: false # Optional flag to run auto-deployment procedure of the FS chain. By default, 'true'. # If set, must be 'true' or 'false'. nns: # Optional configuration of the NNS domains processed during the FS chain deployment @@ -118,6 +118,15 @@ nns: # Optional configuration of the NNS domains processed during the FS chain d # Defaults to 'nonexistent@nspcc.io' mainnet: + enabled: false # Enable connection to mainchain; by default, 'false', run application in single chain environment + # without mainchain; value revert deprecated 'without_mainnet' + disable_governance_sync: false # Disable synchronization of sidechain committee and mainchain role management contract; + # ignore if mainchain is disabled; same as 'governance.disable' + extra_fee: 50000000 # Fixed8 value of extra GAS fee for mainchain contract invocation; ignore if notary is enabled in mainchain; + # same as 'fee.main_chain' + contracts: # same as 'contracts' + neofs: ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62 # Address of NeoFS contract in mainchain; ignore if mainchain is disabled + processing: 597f5894867113a41e192801709c02497f611de8 # Address of processing contract in mainchain; ignore if mainchain is disabled dial_timeout: 1m # Timeout for RPC client connection to mainchain; ignore if mainchain is disabled reconnections_number: 5 # number of reconnection attempts reconnections_delay: 5s # time delay b/w reconnection attempts diff --git a/pkg/innerring/config/config.go b/pkg/innerring/config/config.go index 3ff915c096..78042f8bd9 100644 --- a/pkg/innerring/config/config.go +++ b/pkg/innerring/config/config.go @@ -22,7 +22,7 @@ type Config struct { NNS NNS `mapstructure:"nns"` - Mainnet BasicChain `mapstructure:"mainnet"` + Mainnet Mainnet `mapstructure:"mainnet"` Control Control `mapstructure:"control"` @@ -131,6 +131,15 @@ type Experimental struct { ChainMetaData bool `mapstructure:"chain_meta_data"` } +// Mainnet configures mainnet chain settings. +type Mainnet struct { + Enabled bool `mapstructure:"enabled"` + DisableGovernanceSync bool `mapstructure:"disable_governance_sync"` + ExtraFee int64 `mapstructure:"extra_fee"` + Contracts Contracts `mapstructure:"contracts"` + BasicChain `mapstructure:",squash"` +} + // IsSet checks if the key is set in the config. func (c *Config) IsSet(key string) bool { _, ok := c.isSet[key] diff --git a/pkg/innerring/config/fschain.go b/pkg/innerring/config/fschain.go index 2e84a6a2f2..91f75192e1 100644 --- a/pkg/innerring/config/fschain.go +++ b/pkg/innerring/config/fschain.go @@ -8,9 +8,10 @@ import ( // Chain configures settings of FS chain. type Chain struct { - BasicChain `mapstructure:",squash"` - Validators keys.PublicKeys `mapstructure:"validators"` - Consensus Consensus `mapstructure:"consensus"` + BasicChain `mapstructure:",squash"` + Validators keys.PublicKeys `mapstructure:"validators"` + Consensus Consensus `mapstructure:"consensus"` + DisableAutodeploy bool `mapstructure:"disable_autodeploy"` } // Consensus configures Blockchain. All required fields must be set. Specified diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index 9f03147817..32057f2c5a 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -418,6 +418,15 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< serveMetrics(server, cfg) + // TODO: remove deprecated 'fschain_autodeploy' config option in future release + if cfg.IsSet("fschain_autodeploy") { + log.Warn("configuration option 'fschain_autodeploy' is deprecated, use 'fschain.disable_autodeploy' with the opposite value instead") + if cfg.IsSet("fschain.disable_autodeploy") { + return nil, fmt.Errorf("'fschain_autodeploy' and 'fschain.disable_autodeploy' set simultaneously") + } + cfg.FSChain.DisableAutodeploy = !cfg.FSChainAutodeploy + } + var localWSClient *rpcclient.WSClient // set if isLocalConsensus only // create FS chain client @@ -472,7 +481,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< fsChainOpts[1] = client.WithLogger(log) fsChainOpts[2] = client.WithSingleClient(localWSClient) - if !cfg.FSChainAutodeploy { + if cfg.FSChain.DisableAutodeploy { fsChainOpts = append(fsChainOpts, client.WithAutoFSChainScope()) } @@ -488,7 +497,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< // fallback to the pure RPC architecture fsChainParams.key = server.key - fsChainParams.withAutoFSChainScope = !cfg.FSChainAutodeploy + fsChainParams.withAutoFSChainScope = cfg.FSChain.DisableAutodeploy server.fsChainClient, err = server.createClient(ctx, fsChainParams, errChan) if err != nil { @@ -496,7 +505,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< } } - if cfg.FSChainAutodeploy { + if !cfg.FSChain.DisableAutodeploy { log.Info("auto-deployment configured, initializing FS chain...") var fschain *fsChain @@ -573,7 +582,15 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< return nil, err } - server.withoutMainNet = cfg.WithoutMainnet + // TODO: remove deprecated 'without_mainnet' config option in future release + if cfg.IsSet("without_mainnet") { + log.Warn("configuration option 'without_mainnet' is deprecated, use 'mainnet.enabled' with the reverted value instead") + if cfg.IsSet("mainnet.enabled") { + return nil, fmt.Errorf("'without_mainnet' and 'mainnet.enabled' set simultaneously") + } + cfg.Mainnet.Enabled = !cfg.WithoutMainnet + } + server.withoutMainNet = !cfg.Mainnet.Enabled if server.withoutMainNet { // This works as long as event Listener starts listening loop once, @@ -585,7 +602,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< mainnetChain := fsChainParams mainnetChain.withAutoFSChainScope = false mainnetChain.name = mainnetPrefix - mainnetChain.cfg = &cfg.Mainnet + mainnetChain.cfg = &cfg.Mainnet.BasicChain mainnetChain.from, err = server.persistate.UInt32(persistateMainChainLastBlockKey) if err != nil { @@ -612,9 +629,18 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< zap.Bool("mainchain_enabled", !server.mainNotaryConfig.disabled), ) + // TODO: remove deprecated 'contracts' config option in future release + if cfg.IsSet("contracts") { + log.Warn("configuration option 'contracts' is deprecated, use 'mainnet.contracts' with the same values instead") + if cfg.IsSet("mainnet.contracts") { + return nil, fmt.Errorf("'contracts' and 'mainnet.contracts' set simultaneously") + } + cfg.Mainnet.Contracts = cfg.Contracts + } + // get all script hashes of contracts server.contracts, err = initContracts(ctx, log, - &cfg.Contracts, + &cfg.Mainnet.Contracts, server.fsChainClient, server.withoutMainNet, server.mainNotaryConfig.disabled, @@ -672,8 +698,17 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< return nil, err } + // TODO: remove deprecated 'fee.main_chain' config option in future release + if cfg.IsSet("fee.main_chain") { + log.Warn("configuration option 'fee.main_chain' is deprecated, use 'mainnet.extra_fee' with the same value instead") + if cfg.IsSet("mainnet.extra_fee") { + return nil, fmt.Errorf("'fee.main_chain' and 'mainnet.extra_fee' set simultaneously") + } + cfg.Mainnet.ExtraFee = cfg.Fee.MainChain + } + neofsCli, err := neofsClient.NewFromMorph(server.mainnetClient, server.contracts.neofs, - fixedn.Fixed8(cfg.Fee.MainChain), neofsClient.TryNotary(), neofsClient.AsAlphabet()) + fixedn.Fixed8(cfg.Mainnet.ExtraFee), neofsClient.TryNotary(), neofsClient.AsAlphabet()) if err != nil { return nil, err } @@ -713,7 +748,16 @@ func New(ctx context.Context, log *zap.Logger, cfg *config.Config, errChan chan< var alphaSync event.Handler - if server.withoutMainNet || cfg.Governance.Disable { + // TODO: remove deprecated 'governance.disable' config option in future release + if cfg.IsSet("governance.disable") { + log.Warn("configuration option 'governance.disable' is deprecated, use 'mainnet.disable_governance_sync' with the same value instead") + if cfg.IsSet("mainnet.disable_governance_sync") { + return nil, fmt.Errorf("'governance.disable' and 'mainnet.disable_governance_sync' set simultaneously") + } + cfg.Mainnet.DisableGovernanceSync = cfg.Governance.Disable + } + + if server.withoutMainNet || cfg.Mainnet.DisableGovernanceSync { alphaSync = func(event.Event) { log.Debug("alphabet keys sync is disabled") }