1// Copyright (C) 2020 Storj Labs, Inc. 2// See LICENSE for copying information. 3 4package compensation 5 6import ( 7 "io" 8 9 "storj.io/common/strictcsv" 10 "storj.io/storj/private/currency" 11) 12 13// Invoice holds the calculations for the amount required to pay to a node 14// for a given pay period. 15type Invoice struct { 16 Period Period `csv:"period"` // The payment period 17 NodeID NodeID `csv:"node-id"` // The node ID 18 NodeCreatedAt UTCDate `csv:"node-created-at"` // When the node was created 19 NodeDisqualified *UTCDate `csv:"node-disqualified"` // When and if the node was disqualified 20 NodeGracefulExit *UTCDate `csv:"node-gracefulexit"` // When and if the node finished a graceful exit 21 NodeWallet string `csv:"node-wallet"` // The node's wallet address 22 NodeWalletFeatures WalletFeatures `csv:"node-wallet-features"` // The node's wallet features 23 NodeAddress string `csv:"node-address"` // The node's TODO 24 NodeLastIP string `csv:"node-last-ip"` // The last known ip the node had 25 Codes Codes `csv:"codes"` // Any codes providing context to the invoice 26 UsageAtRest float64 `csv:"usage-at-rest"` // Byte-hours provided during the payment period 27 UsageGet int64 `csv:"usage-get"` // Number of bytes served in GET requests 28 UsagePut int64 `csv:"usage-put"` // Number of bytes served in PUT requests 29 UsageGetRepair int64 `csv:"usage-get-repair"` // Number of bytes served in GET_REPAIR requests 30 UsagePutRepair int64 `csv:"usage-put-repair"` // Number of bytes served in PUT_REPAIR requests 31 UsageGetAudit int64 `csv:"usage-get-audit"` // Number of bytes served in GET_AUDIT requests 32 CompAtRest currency.MicroUnit `csv:"comp-at-rest"` // Compensation for usage-at-rest 33 CompGet currency.MicroUnit `csv:"comp-get"` // Compensation for usage-get 34 CompPut currency.MicroUnit `csv:"comp-put"` // Compensation for usage-put 35 CompGetRepair currency.MicroUnit `csv:"comp-get-repair"` // Compensation for usage-get-repair 36 CompPutRepair currency.MicroUnit `csv:"comp-put-repair"` // Compensation for usage-put-repair 37 CompGetAudit currency.MicroUnit `csv:"comp-get-audit"` // Compensation for usage-get-audit 38 SurgePercent int64 `csv:"surge-percent"` // Surge percent used to calculate compensation, or 0 if no surge 39 Owed currency.MicroUnit `csv:"owed"` // Amount we intend to pay to the node (sum(comp-*) - held + disposed) 40 Held currency.MicroUnit `csv:"held"` // Amount held from sum(comp-*) for this period 41 Disposed currency.MicroUnit `csv:"disposed"` // Amount of owed that is due to graceful-exit or held period ending 42 TotalHeld currency.MicroUnit `csv:"total-held"` // Total amount ever held from the node 43 TotalDisposed currency.MicroUnit `csv:"total-disposed"` // Total amount ever disposed to the node 44 TotalPaid currency.MicroUnit `csv:"total-paid"` // Total amount ever paid to the node (but not necessarily dispensed) 45 TotalDistributed currency.MicroUnit `csv:"total-distributed"` // Total amount ever distributed to the node (always less than or equal to paid) 46} 47 48// MergeNodeInfo updates the fields representing the node information into the invoice. 49func (invoice *Invoice) MergeNodeInfo(nodeInfo NodeInfo) error { 50 if invoice.NodeID != NodeID(nodeInfo.ID) { 51 return Error.New("node ID mismatch (invoice=%q nodeinfo=%q)", invoice.NodeID, nodeInfo.ID) 52 } 53 invoice.NodeCreatedAt = UTCDate(nodeInfo.CreatedAt) 54 invoice.NodeDisqualified = (*UTCDate)(nodeInfo.Disqualified) 55 invoice.NodeGracefulExit = (*UTCDate)(nodeInfo.GracefulExit) 56 invoice.UsageAtRest = nodeInfo.UsageAtRest 57 invoice.UsageGet = nodeInfo.UsageGet 58 invoice.UsagePut = nodeInfo.UsagePut 59 invoice.UsageGetRepair = nodeInfo.UsageGetRepair 60 invoice.UsagePutRepair = nodeInfo.UsagePutRepair 61 invoice.UsageGetAudit = nodeInfo.UsageGetAudit 62 invoice.TotalHeld = nodeInfo.TotalHeld 63 invoice.TotalDisposed = nodeInfo.TotalDisposed 64 invoice.TotalPaid = nodeInfo.TotalPaid 65 invoice.TotalDistributed = nodeInfo.TotalDistributed 66 return nil 67} 68 69// MergeStatement updates the fields representing the calculation of the payment amounts 70// into the invoice. 71func (invoice *Invoice) MergeStatement(statement Statement) error { 72 if invoice.NodeID != NodeID(statement.NodeID) { 73 return Error.New("node ID mismatch (invoice=%q statement=%q)", invoice.NodeID, statement.NodeID) 74 } 75 invoice.Codes = statement.Codes 76 invoice.CompAtRest = statement.AtRest 77 invoice.CompGet = statement.Get 78 invoice.CompPut = statement.Put 79 invoice.CompGetRepair = statement.GetRepair 80 invoice.CompPutRepair = statement.PutRepair 81 invoice.CompGetAudit = statement.GetAudit 82 invoice.SurgePercent = statement.SurgePercent 83 invoice.Owed = statement.Owed 84 invoice.Held = statement.Held 85 invoice.Disposed = statement.Disposed 86 return nil 87} 88 89// ReadInvoices reads a collection of Invoice values in CSV form. 90func ReadInvoices(r io.Reader) ([]Invoice, error) { 91 var invoices []Invoice 92 if err := strictcsv.Read(r, &invoices); err != nil { 93 return nil, err 94 } 95 return invoices, nil 96} 97 98// WriteInvoices writes a collection of Invoice values in CSV form. 99func WriteInvoices(w io.Writer, invoices []Invoice) error { 100 return strictcsv.Write(w, invoices) 101} 102