satellite/compensation: add offline status tracking
Change-Id: I52e615d3db186416ee95029dc72df626f0e69ad7
This commit is contained in:
parent
cafa7a5f0b
commit
42f63c6538
@ -81,18 +81,19 @@ func generateInvoicesCSV(ctx context.Context, period compensation.Period, out io
|
||||
}
|
||||
|
||||
nodeInfo := compensation.NodeInfo{
|
||||
ID: usage.NodeID,
|
||||
CreatedAt: node.CreatedAt,
|
||||
Disqualified: node.Disqualified,
|
||||
GracefulExit: gracefulExit,
|
||||
UsageAtRest: usage.AtRestTotal,
|
||||
UsageGet: usage.GetTotal,
|
||||
UsagePut: usage.PutTotal,
|
||||
UsageGetRepair: usage.GetRepairTotal,
|
||||
UsagePutRepair: usage.PutRepairTotal,
|
||||
UsageGetAudit: usage.GetAuditTotal,
|
||||
TotalHeld: withheldAmounts.TotalHeld,
|
||||
TotalDisposed: withheldAmounts.TotalDisposed,
|
||||
ID: usage.NodeID,
|
||||
CreatedAt: node.CreatedAt,
|
||||
LastContactSuccess: node.Reputation.LastContactSuccess,
|
||||
Disqualified: node.Disqualified,
|
||||
GracefulExit: gracefulExit,
|
||||
UsageAtRest: usage.AtRestTotal,
|
||||
UsageGet: usage.GetTotal,
|
||||
UsagePut: usage.PutTotal,
|
||||
UsageGetRepair: usage.GetRepairTotal,
|
||||
UsagePutRepair: usage.PutRepairTotal,
|
||||
UsageGetAudit: usage.GetAuditTotal,
|
||||
TotalHeld: withheldAmounts.TotalHeld,
|
||||
TotalDisposed: withheldAmounts.TotalDisposed,
|
||||
}
|
||||
|
||||
invoice := compensation.Invoice{
|
||||
|
@ -26,13 +26,17 @@ const (
|
||||
|
||||
// GracefulExit is included if the node has gracefully exited.
|
||||
GracefulExit Code = "X"
|
||||
|
||||
// Offline is included if the node's last contact success is before the starting
|
||||
// period.
|
||||
Offline Code = "O"
|
||||
)
|
||||
|
||||
// CodeFromString parses the string into a Code.
|
||||
func CodeFromString(s string) (Code, error) {
|
||||
code := Code(s)
|
||||
switch code {
|
||||
case Disqualified, Sanctioned, No1099, InWithholding, GracefulExit:
|
||||
case Disqualified, Sanctioned, No1099, InWithholding, GracefulExit, Offline:
|
||||
return code, nil
|
||||
default:
|
||||
return "", Error.New("no such code %q", code)
|
||||
|
@ -36,18 +36,19 @@ var (
|
||||
// NodeInfo contains all of the information about a node and the operations
|
||||
// it performed in some period.
|
||||
type NodeInfo struct {
|
||||
ID storj.NodeID
|
||||
CreatedAt time.Time
|
||||
Disqualified *time.Time
|
||||
GracefulExit *time.Time
|
||||
UsageAtRest float64
|
||||
UsageGet int64
|
||||
UsagePut int64
|
||||
UsageGetRepair int64
|
||||
UsagePutRepair int64
|
||||
UsageGetAudit int64
|
||||
TotalHeld currency.MicroUnit
|
||||
TotalDisposed currency.MicroUnit
|
||||
ID storj.NodeID
|
||||
CreatedAt time.Time
|
||||
LastContactSuccess time.Time
|
||||
Disqualified *time.Time
|
||||
GracefulExit *time.Time
|
||||
UsageAtRest float64
|
||||
UsageGet int64
|
||||
UsagePut int64
|
||||
UsageGetRepair int64
|
||||
UsagePutRepair int64
|
||||
UsageGetAudit int64
|
||||
TotalHeld currency.MicroUnit
|
||||
TotalDisposed currency.MicroUnit
|
||||
}
|
||||
|
||||
// Statement is the computed amounts and codes from a node.
|
||||
@ -98,6 +99,7 @@ type PeriodInfo struct {
|
||||
|
||||
// GenerateStatements generates all of the Statements for the given PeriodInfo.
|
||||
func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
||||
startDate := info.Period.StartDate()
|
||||
endDate := info.Period.EndDateExclusive()
|
||||
|
||||
rates := info.Rates
|
||||
@ -150,6 +152,11 @@ func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
||||
codes = append(codes, GracefulExit)
|
||||
}
|
||||
|
||||
offline := node.LastContactSuccess.Before(startDate)
|
||||
if offline {
|
||||
codes = append(codes, Offline)
|
||||
}
|
||||
|
||||
withheldPercent, inWithholding := NodeWithheldPercent(withheldPercents, node.CreatedAt, endDate)
|
||||
held := PercentOf(total, decimal.NewFromInt(int64(withheldPercent)))
|
||||
owed := total.Sub(held)
|
||||
@ -177,7 +184,7 @@ func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
||||
owed = owed.Add(disposed)
|
||||
}
|
||||
|
||||
// If the node is disqualified nothing is owed/held/disposed.
|
||||
// If the node is disqualified but not gracefully exited, nothing is owed/held/disposed.
|
||||
if node.Disqualified != nil && node.Disqualified.Before(endDate) && !gracefullyExited {
|
||||
codes = append(codes, Disqualified)
|
||||
disposed = decimal.Zero
|
||||
@ -185,6 +192,13 @@ func GenerateStatements(info PeriodInfo) ([]Statement, error) {
|
||||
owed = decimal.Zero
|
||||
}
|
||||
|
||||
// If the node is offline, nothing is owed/held/disposed.
|
||||
if offline {
|
||||
disposed = decimal.Zero
|
||||
held = decimal.Zero
|
||||
owed = decimal.Zero
|
||||
}
|
||||
|
||||
var overflowErrs errs.Group
|
||||
toMicroUnit := func(v decimal.Decimal) currency.MicroUnit {
|
||||
m, err := currency.MicroUnitFromDecimal(v)
|
||||
|
@ -52,14 +52,15 @@ func TestGenerateStatements(t *testing.T) {
|
||||
name: "within withholding",
|
||||
surgePercent: 0,
|
||||
node: compensation.NodeInfo{
|
||||
ID: nodeID,
|
||||
CreatedAt: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
ID: nodeID,
|
||||
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
CreatedAt: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
},
|
||||
statement: compensation.Statement{
|
||||
NodeID: nodeID,
|
||||
@ -79,15 +80,16 @@ func TestGenerateStatements(t *testing.T) {
|
||||
name: "just out of withheld",
|
||||
surgePercent: 0,
|
||||
node: compensation.NodeInfo{
|
||||
ID: nodeID,
|
||||
CreatedAt: time.Date(2019, 11, 1, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
TotalHeld: D(40),
|
||||
ID: nodeID,
|
||||
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
CreatedAt: time.Date(2019, 11, 1, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
TotalHeld: D(40),
|
||||
},
|
||||
statement: compensation.Statement{
|
||||
NodeID: nodeID,
|
||||
@ -106,16 +108,17 @@ func TestGenerateStatements(t *testing.T) {
|
||||
name: "out of withheld and already disposed",
|
||||
surgePercent: 0,
|
||||
node: compensation.NodeInfo{
|
||||
ID: nodeID,
|
||||
CreatedAt: time.Date(2019, 6, 12, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
TotalHeld: D(40),
|
||||
TotalDisposed: D(24),
|
||||
ID: nodeID,
|
||||
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
CreatedAt: time.Date(2019, 6, 12, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
TotalHeld: D(40),
|
||||
TotalDisposed: D(24),
|
||||
},
|
||||
statement: compensation.Statement{
|
||||
NodeID: nodeID,
|
||||
@ -134,17 +137,18 @@ func TestGenerateStatements(t *testing.T) {
|
||||
name: "graceful exit within period",
|
||||
surgePercent: 0,
|
||||
node: compensation.NodeInfo{
|
||||
ID: nodeID,
|
||||
CreatedAt: time.Date(2018, 6, 12, 0, 0, 0, 0, time.UTC),
|
||||
GracefulExit: timePtr(time.Date(2019, 11, 30, 23, 59, 59, 0, time.UTC)),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
TotalHeld: D(40),
|
||||
TotalDisposed: D(24),
|
||||
ID: nodeID,
|
||||
LastContactSuccess: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
CreatedAt: time.Date(2018, 6, 12, 0, 0, 0, 0, time.UTC),
|
||||
GracefulExit: timePtr(time.Date(2019, 11, 30, 23, 59, 59, 0, time.UTC)),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
TotalHeld: D(40),
|
||||
TotalDisposed: D(24),
|
||||
},
|
||||
statement: compensation.Statement{
|
||||
NodeID: nodeID,
|
||||
@ -160,6 +164,34 @@ func TestGenerateStatements(t *testing.T) {
|
||||
Disposed: D(16),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "offline",
|
||||
surgePercent: 0,
|
||||
node: compensation.NodeInfo{
|
||||
ID: nodeID,
|
||||
LastContactSuccess: time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC),
|
||||
CreatedAt: time.Date(2019, 11, 2, 0, 0, 0, 0, time.UTC),
|
||||
UsageAtRest: 1 * GB,
|
||||
UsageGet: 2 * TB,
|
||||
UsagePut: 3 * TB,
|
||||
UsageGetRepair: 4 * TB,
|
||||
UsagePutRepair: 5 * TB,
|
||||
UsageGetAudit: 6 * TB,
|
||||
},
|
||||
statement: compensation.Statement{
|
||||
NodeID: nodeID,
|
||||
Codes: compensation.Codes{compensation.Offline, compensation.InWithholding},
|
||||
AtRest: D(2),
|
||||
Get: D(6),
|
||||
Put: D(15),
|
||||
GetRepair: D(28),
|
||||
PutRepair: D(55),
|
||||
GetAudit: D(78),
|
||||
Owed: D(0),
|
||||
Held: D(0),
|
||||
Disposed: D(0),
|
||||
},
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user