From f2be8568642b50fa8462cb6483bb6a707cebd0bc Mon Sep 17 00:00:00 2001 From: Qweder93 Date: Sun, 21 Feb 2021 17:22:44 +0200 Subject: [PATCH] storagenode/payouts: estimated payouts calculations upgraded Added recalculations of estimated income in current month in case node joined in current month Change-Id: Iac925fd8bcf2be8f1089e5f001a01448ba7650be --- .../console/consoleapi/storagenode_test.go | 8 +- .../estimatedpayouts/estimatedpayouts.go | 47 ++- .../estimatedpayouts/estimatedpayouts_test.go | 330 ++++++++++++++++-- .../payouts/estimatedpayouts/service.go | 39 +-- 4 files changed, 353 insertions(+), 71 deletions(-) diff --git a/storagenode/console/consoleapi/storagenode_test.go b/storagenode/console/consoleapi/storagenode_test.go index fbef41ebc..a71d8fa2d 100644 --- a/storagenode/console/consoleapi/storagenode_test.go +++ b/storagenode/console/consoleapi/storagenode_test.go @@ -17,6 +17,7 @@ import ( "storj.io/common/pb" "storj.io/common/storj" "storj.io/common/testcontext" + "storj.io/storj/private/date" "storj.io/storj/private/testplanet" "storj.io/storj/satellite" "storj.io/storj/storagenode/payouts/estimatedpayouts" @@ -94,15 +95,19 @@ func TestStorageNodeApi(t *testing.T) { }) require.NoError(t, err) + now2 := time.Now().UTC() + daysPerMonth := date.UTCEndOfMonth(now2).Day() + err = reputationdb.Store(ctx, reputation.Stats{ SatelliteID: satellite.ID(), - JoinedAt: time.Now().UTC(), + JoinedAt: now.AddDate(0, 0, -daysPerMonth+3), }) require.NoError(t, err) t.Run("test EstimatedPayout", func(t *testing.T) { // should return estimated payout for both satellites in current month and empty for previous url := fmt.Sprintf("%s/estimated-payout", baseURL) + res, err := http.Get(url) require.NoError(t, err) require.NotNil(t, res) @@ -122,7 +127,6 @@ func TestStorageNodeApi(t *testing.T) { PreviousMonth: estimation.PreviousMonth, CurrentMonthExpectations: estimation.CurrentMonthExpectations, }) - require.NoError(t, err) require.Equal(t, string(expected)+"\n", string(body)) }) diff --git a/storagenode/payouts/estimatedpayouts/estimatedpayouts.go b/storagenode/payouts/estimatedpayouts/estimatedpayouts.go index c9af9846a..d972bce2c 100644 --- a/storagenode/payouts/estimatedpayouts/estimatedpayouts.go +++ b/storagenode/payouts/estimatedpayouts/estimatedpayouts.go @@ -60,20 +60,49 @@ func (pm *PayoutMonthly) SetPayout() { pm.Payout = RoundFloat(amount) } +// Add sums payout monthly data. +func (pm *PayoutMonthly) Add(monthly PayoutMonthly) { + pm.Payout += monthly.Payout + pm.EgressRepairAuditPayout += monthly.EgressRepairAuditPayout + pm.DiskSpacePayout += monthly.DiskSpacePayout + pm.DiskSpace += monthly.DiskSpace + pm.EgressBandwidth += monthly.EgressBandwidth + pm.EgressBandwidthPayout += monthly.EgressBandwidthPayout + pm.EgressRepairAudit += monthly.EgressRepairAudit + pm.Held += monthly.Held +} + // RoundFloat rounds float value till 2 signs after dot. func RoundFloat(value float64) float64 { return math.Round(value*100) / 100 } -// SetExpectedMonth set current month expectations. -func (estimatedPayout *EstimatedPayout) SetExpectedMonth(now time.Time) { - daysPast := float64(now.Day()) - 1 - if daysPast < 1 { - daysPast = 1 +// Set set's estimated payout with current/previous PayoutMonthly's data and current month expectations. +func (estimatedPayout *EstimatedPayout) Set(current, previous PayoutMonthly, now, joinedAt time.Time) { + estimatedPayout.CurrentMonth = current + estimatedPayout.PreviousMonth = previous + + daysSinceJoined := now.Sub(joinedAt).Hours() / 24 + daysPerMonth := float64(date.UTCEndOfMonth(now).Day()) + + if daysSinceJoined >= float64(now.Day()) { + daysPast := float64(now.Day()) - 1 + if daysPast < 1 { + daysPast = 1 + } + + payoutPerDay := estimatedPayout.CurrentMonth.Payout / daysPast + + estimatedPayout.CurrentMonthExpectations += payoutPerDay * daysPerMonth + return } - daysPerMonth := float64(date.UTCEndOfMonth(now).Day()) - payoutPerDay := estimatedPayout.CurrentMonth.Payout / daysPast - - estimatedPayout.CurrentMonthExpectations += payoutPerDay * daysPerMonth + estimatedPayout.CurrentMonthExpectations += estimatedPayout.CurrentMonth.Payout / daysSinceJoined * daysPerMonth +} + +// Add adds estimate into the receiver. +func (estimatedPayout *EstimatedPayout) Add(other EstimatedPayout) { + estimatedPayout.CurrentMonth.Add(other.CurrentMonth) + estimatedPayout.PreviousMonth.Add(other.PreviousMonth) + estimatedPayout.CurrentMonthExpectations += other.CurrentMonthExpectations } diff --git a/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go b/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go index 5dcae105a..05ae900ec 100644 --- a/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go +++ b/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go @@ -10,41 +10,309 @@ import ( "github.com/stretchr/testify/require" - "storj.io/common/testcontext" - "storj.io/storj/private/testplanet" "storj.io/storj/storagenode/payouts/estimatedpayouts" ) func TestCurrentMonthExpectations(t *testing.T) { - testplanet.Run(t, testplanet.Config{ - StorageNodeCount: 1, - SatelliteCount: 2, - }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { - const payout = 100.0 + const payout = 100.0 - type test struct { - time time.Time - expected float64 - } - tests := []test{ - // 28 days in month - {time.Date(2021, 2, 1, 16, 0, 0, 0, time.UTC), 2800.00}, - {time.Date(2021, 2, 28, 10, 0, 0, 0, time.UTC), 103.70}, - // 31 days in month - {time.Date(2021, 3, 1, 19, 0, 0, 0, time.UTC), 3100.0}, - {time.Date(2021, 3, 31, 21, 0, 0, 0, time.UTC), 103.33}, - } + type test struct { + time time.Time + expected float64 + joinedAt time.Time + payout estimatedpayouts.EstimatedPayout + current, previous estimatedpayouts.PayoutMonthly + } + tests := []test{ + // 28 days in month + {time.Date(2021, 2, 1, 16, 0, 0, 0, time.UTC), 2800.00, time.Date(2021, 1, 1, 12, 0, 0, 0, time.UTC), + estimatedpayouts.EstimatedPayout{}, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }}, + {time.Date(2021, 2, 28, 10, 0, 0, 0, time.UTC), 103.70, time.Date(2021, 1, 26, 10, 0, 0, 0, time.UTC), + estimatedpayouts.EstimatedPayout{}, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }}, + {time.Date(2021, 2, 28, 10, 0, 0, 0, time.UTC), 215.38, time.Date(2021, 2, 15, 10, 0, 0, 0, time.UTC), + estimatedpayouts.EstimatedPayout{}, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }}, + // 31 days in month + {time.Date(2021, 3, 1, 19, 0, 0, 0, time.UTC), 3100.0, time.Date(2021, 1, 1, 19, 0, 0, 0, time.UTC), + estimatedpayouts.EstimatedPayout{}, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }}, + {time.Date(2021, 3, 31, 21, 0, 0, 0, time.UTC), 103.33, time.Date(2021, 1, 31, 21, 0, 0, 0, time.UTC), + estimatedpayouts.EstimatedPayout{}, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }}, + {time.Date(2021, 3, 31, 21, 0, 0, 0, time.UTC), 193.75, time.Date(2021, 3, 15, 21, 0, 0, 0, time.UTC), + estimatedpayouts.EstimatedPayout{}, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }, + estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 567, + DiskSpacePayout: 678, + HeldRate: 789, + Payout: payout, + Held: 901, + }}, + } - for _, test := range tests { - estimates := estimatedpayouts.EstimatedPayout{ - CurrentMonth: estimatedpayouts.PayoutMonthly{ - Payout: payout, - }, - } - - estimates.SetExpectedMonth(test.time) - require.False(t, math.IsNaN(estimates.CurrentMonthExpectations)) - require.InDelta(t, test.expected, estimates.CurrentMonthExpectations, 0.01) - } - }) + for _, test := range tests { + test.payout.Set(test.current, test.previous, test.time, test.joinedAt) + require.False(t, math.IsNaN(test.payout.CurrentMonthExpectations)) + require.InDelta(t, test.expected, test.payout.CurrentMonthExpectations, 0.01) + require.Equal(t, test.payout.CurrentMonth, test.current) + require.Equal(t, test.payout.PreviousMonth, test.previous) + } +} + +func TestAddEstimationPayout(t *testing.T) { + type test struct { + basic, addition, result estimatedpayouts.EstimatedPayout + } + + tests := []test{ + {estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 123, + EgressRepairAudit: 123, + EgressRepairAuditPayout: 123, + DiskSpace: 123, + DiskSpacePayout: 123, + Payout: 123, + Held: 123, + }, + PreviousMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 234, + EgressBandwidthPayout: 234, + EgressRepairAudit: 234, + EgressRepairAuditPayout: 234, + DiskSpace: 234, + DiskSpacePayout: 234, + Payout: 234, + Held: 234, + }, + CurrentMonthExpectations: 111, + }, + estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 345, + EgressBandwidthPayout: 345, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 345, + DiskSpace: 345, + DiskSpacePayout: 345, + Payout: 345, + Held: 345, + }, + PreviousMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 456, + EgressBandwidthPayout: 456, + EgressRepairAudit: 456, + EgressRepairAuditPayout: 456, + DiskSpace: 456, + DiskSpacePayout: 456, + Payout: 456, + Held: 456, + }, + CurrentMonthExpectations: 222, + }, + estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 468, + EgressBandwidthPayout: 468, + EgressRepairAudit: 468, + EgressRepairAuditPayout: 468, + DiskSpace: 468, + DiskSpacePayout: 468, + Payout: 468, + Held: 468, + }, + PreviousMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 690, + EgressBandwidthPayout: 690, + EgressRepairAudit: 690, + EgressRepairAuditPayout: 690, + DiskSpace: 690, + DiskSpacePayout: 690, + Payout: 690, + Held: 690, + }, + CurrentMonthExpectations: 333, + }}, + {estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + }, + PreviousMonth: estimatedpayouts.PayoutMonthly{ + DiskSpace: 123, + DiskSpacePayout: 234, + Payout: 345, + Held: 456, + }, + CurrentMonthExpectations: 111, + }, + estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + DiskSpace: 456, + DiskSpacePayout: 345, + Payout: 234, + Held: 123, + }, + PreviousMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 456, + EgressBandwidthPayout: 345, + EgressRepairAudit: 234, + EgressRepairAuditPayout: 123, + }, + CurrentMonthExpectations: 111, + }, + estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 123, + EgressBandwidthPayout: 234, + EgressRepairAudit: 345, + EgressRepairAuditPayout: 456, + DiskSpace: 456, + DiskSpacePayout: 345, + Payout: 234, + Held: 123, + }, + PreviousMonth: estimatedpayouts.PayoutMonthly{ + EgressBandwidth: 456, + EgressBandwidthPayout: 345, + EgressRepairAudit: 234, + EgressRepairAuditPayout: 123, + DiskSpace: 123, + DiskSpacePayout: 234, + Payout: 345, + Held: 456, + }, + CurrentMonthExpectations: 222, + }}, + } + + for _, test := range tests { + test.basic.Add(test.addition) + require.Equal(t, test.basic, test.result) + } } diff --git a/storagenode/payouts/estimatedpayouts/service.go b/storagenode/payouts/estimatedpayouts/service.go index 66c942f37..dc710a835 100644 --- a/storagenode/payouts/estimatedpayouts/service.go +++ b/storagenode/payouts/estimatedpayouts/service.go @@ -61,22 +61,12 @@ func (s *Service) GetSatelliteEstimatedPayout(ctx context.Context, satelliteID s return EstimatedPayout{}, EstimationServiceErr.Wrap(err) } - payout.CurrentMonth = currentMonthPayout - payout.PreviousMonth = previousMonthPayout - stats, err := s.reputationDB.Get(ctx, satelliteID) if err != nil { return EstimatedPayout{}, EstimationServiceErr.Wrap(err) } - daysSinceJoined := now.Sub(stats.JoinedAt).Hours() / 24 - if daysSinceJoined >= float64(now.Day()) { - payout.SetExpectedMonth(now) - - return payout, nil - } - - payout.CurrentMonthExpectations = (payout.CurrentMonth.Payout / daysSinceJoined) * float64(date.UTCEndOfMonth(now).Day()) + payout.Set(currentMonthPayout, previousMonthPayout, now, stats.JoinedAt) return payout, nil } @@ -91,25 +81,16 @@ func (s *Service) GetAllSatellitesEstimatedPayout(ctx context.Context, now time. return EstimatedPayout{}, EstimationServiceErr.Wrap(err) } - payout.CurrentMonth.Payout += current.Payout - payout.CurrentMonth.EgressRepairAuditPayout += current.EgressRepairAuditPayout - payout.CurrentMonth.DiskSpacePayout += current.DiskSpacePayout - payout.CurrentMonth.DiskSpace += current.DiskSpace - payout.CurrentMonth.EgressBandwidth += current.EgressBandwidth - payout.CurrentMonth.EgressBandwidthPayout += current.EgressBandwidthPayout - payout.CurrentMonth.EgressRepairAudit += current.EgressRepairAudit - payout.CurrentMonth.Held += current.Held - payout.PreviousMonth.Payout += previous.Payout - payout.PreviousMonth.DiskSpacePayout += previous.DiskSpacePayout - payout.PreviousMonth.DiskSpace += previous.DiskSpace - payout.PreviousMonth.EgressBandwidth += previous.EgressBandwidth - payout.PreviousMonth.EgressBandwidthPayout += previous.EgressBandwidthPayout - payout.PreviousMonth.EgressRepairAuditPayout += previous.EgressRepairAuditPayout - payout.PreviousMonth.EgressRepairAudit += previous.EgressRepairAudit - payout.PreviousMonth.Held += previous.Held - } + var satellitePayout EstimatedPayout - payout.SetExpectedMonth(now) + stats, err := s.reputationDB.Get(ctx, satelliteIDs[i]) + if err != nil { + return EstimatedPayout{}, EstimationServiceErr.Wrap(err) + } + + satellitePayout.Set(current, previous, now, stats.JoinedAt) + payout.Add(satellitePayout) + } return payout, nil }