diff --git a/cmd/satellite/compensation.go b/cmd/satellite/compensation.go index dc467d6da..c36070797 100644 --- a/cmd/satellite/compensation.go +++ b/cmd/satellite/compensation.go @@ -12,7 +12,6 @@ import ( "github.com/zeebo/errs" "go.uber.org/zap" - "storj.io/storj/private/currency" "storj.io/storj/satellite/compensation" "storj.io/storj/satellite/satellitedb" ) @@ -51,7 +50,7 @@ func generateInvoicesCSV(ctx context.Context, period compensation.Period, out io invoices := make([]compensation.Invoice, 0, len(periodUsage)) for _, usage := range periodUsage { - withheldAmounts, err := db.Compensation().QueryWithheldAmounts(ctx, usage.NodeID) + totalAmounts, err := db.Compensation().QueryTotalAmounts(ctx, usage.NodeID) if err != nil { return err } @@ -89,8 +88,10 @@ func generateInvoicesCSV(ctx context.Context, period compensation.Period, out io UsageGetRepair: usage.GetRepairTotal, UsagePutRepair: usage.PutRepairTotal, UsageGetAudit: usage.GetAuditTotal, - TotalHeld: withheldAmounts.TotalHeld, - TotalDisposed: withheldAmounts.TotalDisposed, + TotalHeld: totalAmounts.TotalHeld, + TotalDisposed: totalAmounts.TotalDisposed, + TotalPaid: totalAmounts.TotalPaid, + TotalDistributed: totalAmounts.TotalDistributed, } invoice := compensation.Invoice{ @@ -99,7 +100,6 @@ func generateInvoicesCSV(ctx context.Context, period compensation.Period, out io NodeWallet: node.Operator.Wallet, NodeAddress: nodeAddress, NodeLastIP: nodeLastIP, - PaidYTD: currency.Zero, // deprecated } if err := invoice.MergeNodeInfo(nodeInfo); err != nil { diff --git a/satellite/compensation/db.go b/satellite/compensation/db.go index 32ae38583..076193fed 100644 --- a/satellite/compensation/db.go +++ b/satellite/compensation/db.go @@ -10,16 +10,23 @@ import ( "storj.io/storj/private/currency" ) -// WithheldAmounts holds the amounts held and disposed. -type WithheldAmounts struct { - TotalHeld currency.MicroUnit - TotalDisposed currency.MicroUnit +// TotalAmounts holds the amounts held and disposed. +// +// Invariants: +// TotalHeld >= TotalDisposed +// TotalPaid >= TotalDisposed +// TotalPaid >= TotalDistributed (we may distribute less due to minimum payout threshold) +type TotalAmounts struct { + TotalHeld currency.MicroUnit // portion from owed that was held back + TotalDisposed currency.MicroUnit // portion from held back that went into paid + TotalPaid currency.MicroUnit // earned amount that is available to be distributed + TotalDistributed currency.MicroUnit // amount actually transferred to the operator } // DB is the interface we need to source the data to calculate compensation. type DB interface { - // QueryWithheldAmounts queries the WithheldAmounts for the given nodeID. - QueryWithheldAmounts(ctx context.Context, nodeID storj.NodeID) (WithheldAmounts, error) + // QueryTotalAmounts queries the WithheldAmounts for the given nodeID. + QueryTotalAmounts(ctx context.Context, nodeID storj.NodeID) (TotalAmounts, error) // RecordPeriod records a set of paystubs and payments for some time period. RecordPeriod(ctx context.Context, paystubs []Paystub, payments []Payment) error diff --git a/satellite/compensation/invoice.go b/satellite/compensation/invoice.go index d966ec7bd..c2382a931 100644 --- a/satellite/compensation/invoice.go +++ b/satellite/compensation/invoice.go @@ -40,7 +40,8 @@ type Invoice struct { Disposed currency.MicroUnit `csv:"disposed"` // Amount of owed that is due to graceful-exit or held period ending TotalHeld currency.MicroUnit `csv:"total-held"` // Total amount ever held from the node TotalDisposed currency.MicroUnit `csv:"total-disposed"` // Total amount ever disposed to the node - PaidYTD currency.MicroUnit `csv:"paid-ytd"` // Deprecated + TotalPaid currency.MicroUnit `csv:"total-paid"` // Total amount ever paid to the node (but not necessarily dispensed) + TotalDistributed currency.MicroUnit `csv:"total-distributed"` // Total amount ever distributed to the node (always less than or equal to paid) } // MergeNodeInfo updates the fields representing the node information into the invoice. @@ -59,6 +60,8 @@ func (invoice *Invoice) MergeNodeInfo(nodeInfo NodeInfo) error { invoice.UsageGetAudit = nodeInfo.UsageGetAudit invoice.TotalHeld = nodeInfo.TotalHeld invoice.TotalDisposed = nodeInfo.TotalDisposed + invoice.TotalPaid = nodeInfo.TotalPaid + invoice.TotalDistributed = nodeInfo.TotalDistributed return nil } diff --git a/satellite/compensation/statement.go b/satellite/compensation/statement.go index a24cb186c..706b01b03 100644 --- a/satellite/compensation/statement.go +++ b/satellite/compensation/statement.go @@ -49,6 +49,8 @@ type NodeInfo struct { UsageGetAudit int64 TotalHeld currency.MicroUnit TotalDisposed currency.MicroUnit + TotalPaid currency.MicroUnit + TotalDistributed currency.MicroUnit } // Statement is the computed amounts and codes from a node. diff --git a/satellite/satellitedb/compensation.go b/satellite/satellitedb/compensation.go index dc7dff5f9..f6cd60273 100644 --- a/satellite/satellitedb/compensation.go +++ b/satellite/satellitedb/compensation.go @@ -16,28 +16,32 @@ type compensationDB struct { db *satelliteDB } -// QueryWithheldAmounts returns withheld data for the given node. -func (comp *compensationDB) QueryWithheldAmounts(ctx context.Context, nodeID storj.NodeID) (_ compensation.WithheldAmounts, err error) { +// QueryTotalAmounts returns withheld data for the given node. +func (comp *compensationDB) QueryTotalAmounts(ctx context.Context, nodeID storj.NodeID) (_ compensation.TotalAmounts, err error) { defer mon.Task()(&ctx)(&err) stmt := comp.db.Rebind(` SELECT coalesce(SUM(held), 0) AS total_held, coalesce(SUM(disposed), 0) AS total_disposed + coalesce(SUM(paid), 0) AS total_paid, + coalesce(SUM(distributed), 0) AS total_distributed FROM storagenode_paystubs WHERE node_id = ? `) - var totalHeld, totalDisposed int64 - if err := comp.db.DB.QueryRow(ctx, stmt, nodeID).Scan(&totalHeld, &totalDisposed); err != nil { - return compensation.WithheldAmounts{}, Error.Wrap(err) + var totalHeld, totalDisposed, totalPaid, totalDistributed int64 + if err := comp.db.DB.QueryRow(ctx, stmt, nodeID).Scan(&totalHeld, &totalDisposed, &totalPaid, &totalDistributed); err != nil { + return compensation.TotalAmounts{}, Error.Wrap(err) } - return compensation.WithheldAmounts{ - TotalHeld: currency.NewMicroUnit(totalHeld), - TotalDisposed: currency.NewMicroUnit(totalDisposed), + return compensation.TotalAmounts{ + TotalHeld: currency.NewMicroUnit(totalHeld), + TotalDisposed: currency.NewMicroUnit(totalDisposed), + TotalPaid: currency.NewMicroUnit(totalPaid), + TotalDistributed: currency.NewMicroUnit(totalDistributed), }, nil }