diff --git a/cmd/neofs-ir/defaults.go b/cmd/neofs-ir/defaults.go index b4d87840f..d90f783a8 100644 --- a/cmd/neofs-ir/defaults.go +++ b/cmd/neofs-ir/defaults.go @@ -104,4 +104,6 @@ func defaultConfiguration(cfg *viper.Viper) { cfg.SetDefault("audit.pdp.max_sleep_interval", "5s") cfg.SetDefault("audit.pdp.pairs_pool_size", "10") cfg.SetDefault("audit.por.pool_size", "10") + + cfg.SetDefault("settlement.basic_income_rate", 0) } diff --git a/pkg/innerring/config/config.go b/pkg/innerring/config/config.go new file mode 100644 index 000000000..61e8e24ce --- /dev/null +++ b/pkg/innerring/config/config.go @@ -0,0 +1,39 @@ +package config + +/* +Config package contains GlobalConfig structure that implements config +reader from both local and global configurations. Most of the time inner ring +does not need this, as for application it has static config with timeouts, +caches sizes etc. However there are routines that use global configuration +values that can be changed in runtime, e.g. basic income rate. Local +configuration value overrides global one so it is easy to debug and test +in different environments. + +Implemented as a part of https://github.com/nspcc-dev/neofs-node/issues/363 +*/ + +import ( + netmapClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper" + "github.com/spf13/viper" +) + +type GlobalConfig struct { + cfg *viper.Viper + nm *netmapClient.Wrapper +} + +func NewGlobalConfigReader(cfg *viper.Viper, nm *netmapClient.Wrapper) *GlobalConfig { + return &GlobalConfig{ + cfg: cfg, + nm: nm, + } +} + +func (c *GlobalConfig) BasicIncomeRate() (uint64, error) { + value := c.cfg.GetUint64("settlement.basic_income_rate") + if value != 0 { + return value, nil + } + + return c.nm.BasinIncomeRate() +} diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index fdc6da487..0126440f2 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/util" crypto "github.com/nspcc-dev/neofs-crypto" + "github.com/nspcc-dev/neofs-node/pkg/innerring/config" "github.com/nspcc-dev/neofs-node/pkg/innerring/invoke" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/alphabet" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit" @@ -238,6 +239,9 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error return nil, err } + // create global runtime config reader + globalConfig := config.NewGlobalConfigReader(cfg, nmClient) + clientCache := newClientCache(&clientCacheParams{ Log: log, Key: server.key, @@ -300,6 +304,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error basicSettlementDeps := &basicIncomeSettlementDeps{ settlementDeps: settlementDeps, cnrClient: cnrClient, + cfg: globalConfig, } auditSettlementCalc := auditSettlement.NewCalculator( diff --git a/pkg/innerring/processors/settlement/basic/collect.go b/pkg/innerring/processors/settlement/basic/collect.go index fb72ace9f..ad205afde 100644 --- a/pkg/innerring/processors/settlement/basic/collect.go +++ b/pkg/innerring/processors/settlement/basic/collect.go @@ -20,11 +20,17 @@ func (inc *IncomeSettlementContext) Collect() { // todo: save state of bank wallet - cachedRate := inc.rate.BasicRate() + cachedRate, err := inc.rate.BasicRate() + if err != nil { + inc.log.Error("can't get basic income rate", + zap.String("error", err.Error())) + + return + } cnrEstimations, err := inc.estimations.Estimations(inc.epoch) if err != nil { - inc.log.Warn("can't fetch container size estimations", + inc.log.Error("can't fetch container size estimations", zap.Uint64("epoch", inc.epoch)) return diff --git a/pkg/innerring/processors/settlement/basic/context.go b/pkg/innerring/processors/settlement/basic/context.go index ac1ced8fe..1b46fbe44 100644 --- a/pkg/innerring/processors/settlement/basic/context.go +++ b/pkg/innerring/processors/settlement/basic/context.go @@ -18,7 +18,7 @@ type ( } RateFetcher interface { - BasicRate() uint64 + BasicRate() (uint64, error) } IncomeSettlementContext struct { diff --git a/pkg/innerring/settlement.go b/pkg/innerring/settlement.go index 9ad277d1a..598fadeeb 100644 --- a/pkg/innerring/settlement.go +++ b/pkg/innerring/settlement.go @@ -26,6 +26,10 @@ import ( "go.uber.org/zap" ) +type globalConfig interface { + BasicIncomeRate() (uint64, error) +} + type settlementDeps struct { log *logger.Logger @@ -47,6 +51,7 @@ type auditSettlementDeps struct { type basicIncomeSettlementDeps struct { *settlementDeps cnrClient *containerClient.Wrapper + cfg globalConfig } type basicSettlementConstructor struct { @@ -226,8 +231,8 @@ func (b basicIncomeSettlementDeps) Transfer(sender, recipient *owner.ID, amount b.transfer(sender, recipient, amount, basicIncomeAuditDetails) } -func (b basicIncomeSettlementDeps) BasicRate() uint64 { - return 1_0000_0000 // fixme: read from config and from chain +func (b basicIncomeSettlementDeps) BasicRate() (uint64, error) { + return b.cfg.BasicIncomeRate() } func (b basicIncomeSettlementDeps) Estimations(epoch uint64) ([]*wrapper.Estimations, error) { diff --git a/pkg/morph/client/netmap/wrapper/config.go b/pkg/morph/client/netmap/wrapper/config.go index 01b7124b7..41c6dc422 100644 --- a/pkg/morph/client/netmap/wrapper/config.go +++ b/pkg/morph/client/netmap/wrapper/config.go @@ -5,24 +5,47 @@ import ( "github.com/pkg/errors" ) -const maxObjectSizeConfig = "MaxObjectSize" +const ( + maxObjectSizeConfig = "MaxObjectSize" + basicIncomeRateConfig = "BasicIncomeRate" +) // MaxObjectSize receives max object size configuration // value through the Netmap contract call. func (w *Wrapper) MaxObjectSize() (uint64, error) { + objectSize, err := w.readUInt64Config(maxObjectSizeConfig) + if err != nil { + return 0, errors.Wrapf(err, "(%T) could not get epoch number", w) + } + + return objectSize, nil +} + +// BasicIncomeRate returns basic income rate configuration value from network +// config in netmap contract. +func (w *Wrapper) BasinIncomeRate() (uint64, error) { + rate, err := w.readUInt64Config(basicIncomeRateConfig) + if err != nil { + return 0, errors.Wrapf(err, "(%T) could not get basic income rate", w) + } + + return rate, nil +} + +func (w *Wrapper) readUInt64Config(key string) (uint64, error) { args := netmap.ConfigArgs{} - args.SetKey([]byte(maxObjectSizeConfig)) + args.SetKey([]byte(key)) vals, err := w.client.Config(args, netmap.IntegerAssert) if err != nil { - return 0, errors.Wrapf(err, "(%T) could not get epoch number", w) + return 0, err } v := vals.Value() sz, ok := v.(int64) if !ok { - return 0, errors.Errorf("(%T) invalid epoch value type %T", w, v) + return 0, errors.Errorf("(%T) invalid value type %T", w, v) } return uint64(sz), nil