storagenode/payouts: estimated payouts calculations upgraded

Added recalculations of estimated income in current month in case
node joined in current month

Change-Id: Iac925fd8bcf2be8f1089e5f001a01448ba7650be
This commit is contained in:
Qweder93 2021-02-21 17:22:44 +02:00 committed by Nikolai Siedov
parent 1af9400a23
commit f2be856864
4 changed files with 353 additions and 71 deletions

View File

@ -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))
})

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}