diff --git a/cmd/neofs-ir/defaults.go b/cmd/neofs-ir/defaults.go index 5ee1504d..b4d87840 100644 --- a/cmd/neofs-ir/defaults.go +++ b/cmd/neofs-ir/defaults.go @@ -78,6 +78,8 @@ func defaultConfiguration(cfg *viper.Viper) { cfg.SetDefault("timers.emit", "0") cfg.SetDefault("timers.stop_estimation.mul", 1) cfg.SetDefault("timers.stop_estimation.div", 1) + cfg.SetDefault("timers.collect_basic_income.mul", 1) + cfg.SetDefault("timers.collect_basic_income.div", 1) cfg.SetDefault("workers.netmap", "10") cfg.SetDefault("workers.balance", "10") diff --git a/pkg/innerring/blocktimer.go b/pkg/innerring/blocktimer.go index fefa4cc6..e84990ce 100644 --- a/pkg/innerring/blocktimer.go +++ b/pkg/innerring/blocktimer.go @@ -3,8 +3,10 @@ package innerring import ( "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/alphabet" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap" + "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement" "github.com/nspcc-dev/neofs-node/pkg/innerring/timers" container "github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper" + "github.com/nspcc-dev/neofs-node/pkg/morph/event" "go.uber.org/zap" ) @@ -24,6 +26,10 @@ type ( epochDuration uint32 // in blocks stopEstimationDMul uint32 // X: X/Y of epoch in blocks stopEstimationDDiv uint32 // Y: X/Y of epoch in blocks + + collectBasicIncome event.Handler // handle collect basic income + collectBasicIncomeDMul uint32 // X: X/Y of epoch in blocks + collectBasicIncomeDDiv uint32 // Y: X/Y of epoch in blocks } emitTimerArgs struct { @@ -80,6 +86,18 @@ func newEpochTimer(args *epochTimerArgs) *timers.BlockTimer { } }) + epochTimer.OnDelta( + args.collectBasicIncomeDMul, + args.collectBasicIncomeDDiv, + func() { + epochN := args.epoch.EpochCounter() + if epochN == 0 { // estimates are invalid in genesis epoch + return + } + + args.collectBasicIncome(settlement.NewBasicIncomeCollectEvent(epochN - 1)) + }) + return epochTimer } diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index b6a48766..fdc6da48 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -297,6 +297,11 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error settlementDeps: settlementDeps, } + basicSettlementDeps := &basicIncomeSettlementDeps{ + settlementDeps: settlementDeps, + cnrClient: cnrClient, + } + auditSettlementCalc := auditSettlement.NewCalculator( &auditSettlement.CalculatorPrm{ ResultStorage: auditCalcDeps, @@ -313,6 +318,8 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error settlementProcessor := settlement.New( settlement.Prm{ AuditProcessor: (*auditSettlementCalculator)(auditSettlementCalc), + BasicIncome: &basicSettlementConstructor{dep: basicSettlementDeps}, + State: server, }, settlement.WithLogger(server.log), ) @@ -430,13 +437,16 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error // initialize epoch timers server.epochTimer = newEpochTimer(&epochTimerArgs{ - l: server.log, - nm: netmapProcessor, - cnrWrapper: cnrClient, - epoch: server, - epochDuration: cfg.GetUint32("timers.epoch"), - stopEstimationDMul: cfg.GetUint32("timers.stop_estimation.mul"), - stopEstimationDDiv: cfg.GetUint32("timers.stop_estimation.div"), + l: server.log, + nm: netmapProcessor, + cnrWrapper: cnrClient, + epoch: server, + epochDuration: cfg.GetUint32("timers.epoch"), + stopEstimationDMul: cfg.GetUint32("timers.stop_estimation.mul"), + stopEstimationDDiv: cfg.GetUint32("timers.stop_estimation.div"), + collectBasicIncome: settlementProcessor.HandleIncomeCollectionEvent, + collectBasicIncomeDMul: cfg.GetUint32("timers.collect_basic_income.mul"), + collectBasicIncomeDDiv: cfg.GetUint32("timers.collect_basic_income.div"), }) server.addBlockTimer(server.epochTimer) diff --git a/pkg/innerring/settlement.go b/pkg/innerring/settlement.go index d71b4f17..9ad277d1 100644 --- a/pkg/innerring/settlement.go +++ b/pkg/innerring/settlement.go @@ -2,6 +2,7 @@ package innerring import ( "context" + "encoding/hex" "math/big" auditAPI "github.com/nspcc-dev/neofs-api-go/pkg/audit" @@ -14,9 +15,12 @@ import ( "github.com/nspcc-dev/neofs-node/pkg/core/container" "github.com/nspcc-dev/neofs-node/pkg/core/netmap" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/audit" + "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/basic" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/common" auditClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/audit/wrapper" balanceClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance/wrapper" + "github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper" + containerClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper" "github.com/nspcc-dev/neofs-node/pkg/util/logger" "github.com/pkg/errors" "go.uber.org/zap" @@ -40,6 +44,15 @@ type auditSettlementDeps struct { *settlementDeps } +type basicIncomeSettlementDeps struct { + *settlementDeps + cnrClient *containerClient.Wrapper +} + +type basicSettlementConstructor struct { + dep *basicIncomeSettlementDeps +} + type auditSettlementCalculator audit.Calculator type containerWrapper containerAPI.Container @@ -171,7 +184,10 @@ func (s settlementDeps) ResolveKey(ni common.NodeInfo) (*owner.ID, error) { return id, nil } -var transferAuditDetails = []byte("settlement-audit") +var ( + transferAuditDetails = []byte("settlement-audit") + basicIncomeAuditDetails = []byte("settlement-basic-income") +) func (s settlementDeps) transfer(sender, recipient *owner.ID, amount *big.Int, details []byte) { log := s.log.With( @@ -206,8 +222,52 @@ func (a auditSettlementDeps) Transfer(sender, recipient *owner.ID, amount *big.I a.transfer(sender, recipient, amount, transferAuditDetails) } +func (b basicIncomeSettlementDeps) Transfer(sender, recipient *owner.ID, amount *big.Int) { + 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) Estimations(epoch uint64) ([]*wrapper.Estimations, error) { + estimationIDs, err := b.cnrClient.ListLoadEstimationsByEpoch(epoch) + if err != nil { + return nil, err + } + + result := make([]*wrapper.Estimations, 0, len(estimationIDs)) + + for i := range estimationIDs { + estimation, err := b.cnrClient.GetUsedSpaceEstimations(estimationIDs[i]) + if err != nil { + b.log.Warn("can't get used space estimation", + zap.String("estimation_id", hex.EncodeToString(estimationIDs[i])), + zap.String("error", err.Error())) + + continue + } + + result = append(result, estimation) + } + + return result, nil +} + func (s *auditSettlementCalculator) ProcessAuditSettlements(epoch uint64) { (*audit.Calculator)(s).Calculate(&audit.CalculatePrm{ Epoch: epoch, }) } + +func (b *basicSettlementConstructor) CreateContext(epoch uint64) (*basic.IncomeSettlementContext, error) { + return basic.NewIncomeSettlementContext(&basic.IncomeSettlementContextPrms{ + Log: b.dep.log, + Epoch: epoch, + Rate: b.dep, + Estimations: b.dep, + Container: b.dep, + Placement: b.dep, + Exchange: b.dep, + }) +}