diff --git a/go.mod b/go.mod index 78d8c443a..fe50f38f2 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ require ( github.com/jackc/pgconn v1.7.0 github.com/jackc/pgtype v1.5.0 github.com/jackc/pgx/v4 v4.9.0 - github.com/jinzhu/now v1.1.1 github.com/jtolds/monkit-hw/v2 v2.0.0-20191108235325-141a0da276b3 github.com/lucas-clemente/quic-go v0.19.3 github.com/mattn/go-sqlite3 v2.0.3+incompatible diff --git a/go.sum b/go.sum index 19ac02ae3..c8e0fadeb 100644 --- a/go.sum +++ b/go.sum @@ -337,8 +337,6 @@ github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= diff --git a/private/date/utils.go b/private/date/utils.go index d1e29e224..a33693868 100644 --- a/private/date/utils.go +++ b/private/date/utils.go @@ -51,3 +51,10 @@ func MonthsBetweenDates(from time.Time, to time.Time) int { func TruncateToHourInNano(t time.Time) int64 { return t.Truncate(1 * time.Hour).UnixNano() } + +// UTCEndOfMonth returns utc end of month (f.e. to get last day in month). +func UTCEndOfMonth(now time.Time) time.Time { + now = now.UTC() + y, m, _ := now.Date() + return time.Date(y, m+1, 1, 0, 0, 0, 0, &time.Location{}).Add(-time.Nanosecond) +} diff --git a/storagenode/payouts/estimatedpayouts/estimatedpayouts.go b/storagenode/payouts/estimatedpayouts/estimatedpayouts.go index 8c6b592bb..7862577a0 100644 --- a/storagenode/payouts/estimatedpayouts/estimatedpayouts.go +++ b/storagenode/payouts/estimatedpayouts/estimatedpayouts.go @@ -5,6 +5,9 @@ package estimatedpayouts import ( "math" + "time" + + "storj.io/storj/private/date" ) // EstimatedPayout contains usage and estimated payouts data for current and previous months. @@ -61,3 +64,10 @@ func (pm *PayoutMonthly) SetPayout() { func RoundFloat(value float64) float64 { return math.Round(value*100) / 100 } + +// SetExpectedMonth set current month expectations. +func (estimatedPayout *EstimatedPayout) SetExpectedMonth(now time.Time) { + daysPaste := float64(now.Day() - 1) + timeInMonth := date.UTCEndOfMonth(now) + estimatedPayout.CurrentMonthExpectations = (estimatedPayout.CurrentMonth.Payout / daysPaste) * float64(timeInMonth.Day()) +} diff --git a/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go b/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go new file mode 100644 index 000000000..f81cc8fd9 --- /dev/null +++ b/storagenode/payouts/estimatedpayouts/estimatedpayouts_test.go @@ -0,0 +1,37 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package estimatedpayouts_test + +import ( + "testing" + "time" + + "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) { + estimatedPayout := estimatedpayouts.EstimatedPayout{ + CurrentMonth: estimatedpayouts.PayoutMonthly{ + Payout: 100, + }, + } + + currentDay := time.Now().Day() - 1 + now := time.Now().UTC() + y, m, _ := now.Date() + daysInMonth := time.Date(y, m+1, 1, 0, 0, 0, -1, &time.Location{}).Day() + + expectations := (estimatedPayout.CurrentMonth.Payout / float64(currentDay)) * float64(daysInMonth) + estimatedPayout.SetExpectedMonth(now) + require.Equal(t, estimatedPayout.CurrentMonthExpectations, expectations) + }) +} diff --git a/storagenode/payouts/estimatedpayouts/service.go b/storagenode/payouts/estimatedpayouts/service.go index 4222f1bae..530c0c24c 100644 --- a/storagenode/payouts/estimatedpayouts/service.go +++ b/storagenode/payouts/estimatedpayouts/service.go @@ -7,7 +7,6 @@ import ( "context" "time" - "github.com/jinzhu/now" "github.com/spacemonkeygo/monkit/v3" "github.com/zeebo/errs" @@ -57,6 +56,7 @@ func NewService(bandwidthDB bandwidth.DB, reputationDB reputation.DB, storageUsa func (s *Service) GetSatelliteEstimatedPayout(ctx context.Context, satelliteID storj.NodeID) (payout EstimatedPayout, err error) { defer mon.Task()(&ctx)(&err) + now := time.Now() currentMonthPayout, previousMonthPayout, err := s.estimatedPayout(ctx, satelliteID) if err != nil { return EstimatedPayout{}, EstimationServiceErr.Wrap(err) @@ -64,14 +64,27 @@ func (s *Service) GetSatelliteEstimatedPayout(ctx context.Context, satelliteID s payout.CurrentMonth = currentMonthPayout payout.PreviousMonth = previousMonthPayout - payout.setExpectations(ctx) + stats, err := s.reputationDB.Get(ctx, satelliteID) + if err != nil { + return EstimatedPayout{}, EstimationServiceErr.Wrap(err) + } + + daysSinceJoined := time.Since(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()) return payout, nil } // GetAllSatellitesEstimatedPayout returns estimated payouts for current and previous months from all satellites with current level of load. func (s *Service) GetAllSatellitesEstimatedPayout(ctx context.Context) (payout EstimatedPayout, err error) { defer mon.Task()(&ctx)(&err) + now := time.Now() satelliteIDs := s.trust.GetSatellites(ctx) for i := 0; i < len(satelliteIDs); i++ { @@ -97,18 +110,12 @@ func (s *Service) GetAllSatellitesEstimatedPayout(ctx context.Context) (payout E payout.PreviousMonth.EgressRepairAudit += previous.EgressRepairAudit payout.PreviousMonth.Held += previous.Held } - payout.setExpectations(ctx) + + payout.SetExpectedMonth(now) return payout, nil } -// setExpectations set current month expectations. -func (estimatedPayout *EstimatedPayout) setExpectations(ctx context.Context) { - daysPaste := float64(time.Now().Day() - 1) - DaysInMonth := float64(now.EndOfMonth().Day()) - estimatedPayout.CurrentMonthExpectations = (estimatedPayout.CurrentMonth.Payout / daysPaste) * DaysInMonth -} - // estimatedPayout returns estimated payouts data for current and previous months from specific satellite. func (s *Service) estimatedPayout(ctx context.Context, satelliteID storj.NodeID) (currentMonthPayout PayoutMonthly, previousMonthPayout PayoutMonthly, err error) { defer mon.Task()(&ctx)(&err) diff --git a/storagenode/peer.go b/storagenode/peer.go index 2434f5bb6..6f2e04a49 100644 --- a/storagenode/peer.go +++ b/storagenode/peer.go @@ -286,6 +286,7 @@ type Peer struct { Storage *multinode.StorageEndpoint Bandwidth *multinode.BandwidthEndpoint Node *multinode.NodeEndpoint + Payout *multinode.PayoutEndpoint } } @@ -799,6 +800,11 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten peer.DB.Reputation(), peer.Storage2.Trust) + peer.Multinode.Payout = multinode.NewPayoutEndpoint( + peer.Log.Named("multinode:payout-endpoint"), + apiKeys, + peer.DB.Payout()) + if err = multinodepb.DRPCRegisterStorage(peer.Server.DRPC(), peer.Multinode.Storage); err != nil { return nil, errs.Combine(err, peer.Close()) } @@ -808,6 +814,9 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten if err = multinodepb.DRPCRegisterNode(peer.Server.DRPC(), peer.Multinode.Node); err != nil { return nil, errs.Combine(err, peer.Close()) } + if err = multinodepb.DRPCRegisterPayout(peer.Server.DRPC(), peer.Multinode.Payout); err != nil { + return nil, errs.Combine(err, peer.Close()) + } } return peer, nil