satellite/heldamount: payments added, endpoind for payments added

Change-Id: Ia2b9580bc353ef614680230c6f82c5bf6ded49c4
This commit is contained in:
Qweder93 2020-06-26 21:43:06 +03:00
parent b878fcc4b2
commit b639ec08d4
6 changed files with 256 additions and 10 deletions

6
go.mod
View File

@ -6,7 +6,7 @@ require (
github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053 github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053
github.com/alicebob/miniredis/v2 v2.11.1 github.com/alicebob/miniredis/v2 v2.11.1
github.com/btcsuite/btcutil v1.0.1 github.com/btcsuite/btcutil v1.0.1
github.com/calebcase/tmpfile v1.0.1 github.com/calebcase/tmpfile v1.0.2-0.20200602150926-3af473ef8439
github.com/cheggaaa/pb/v3 v3.0.1 github.com/cheggaaa/pb/v3 v3.0.1
github.com/fatih/color v1.7.0 github.com/fatih/color v1.7.0
github.com/go-redis/redis v6.14.1+incompatible github.com/go-redis/redis v6.14.1+incompatible
@ -39,8 +39,8 @@ require (
golang.org/x/sys v0.0.0-20200610111108-226ff32320da golang.org/x/sys v0.0.0-20200610111108-226ff32320da
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/time v0.0.0-20191024005414-555d28b269f0
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 // indirect golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 // indirect
storj.io/common v0.0.0-20200622152042-376f8bec9266 storj.io/common v0.0.0-20200701134427-63fe7147a3f3
storj.io/drpc v0.0.12 storj.io/drpc v0.0.13
storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b
storj.io/private v0.0.0-20200605221229-3236fe879ab3 storj.io/private v0.0.0-20200605221229-3236fe879ab3
storj.io/uplink v1.1.2-0.20200616134034-15d9aa571aa7 storj.io/uplink v1.1.2-0.20200616134034-15d9aa571aa7

6
go.sum
View File

@ -62,6 +62,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/calebcase/tmpfile v1.0.1 h1:vD8FSrbsbexhep39/6mvtbIHS3GzIRqiprDNCF6QqSk= github.com/calebcase/tmpfile v1.0.1 h1:vD8FSrbsbexhep39/6mvtbIHS3GzIRqiprDNCF6QqSk=
github.com/calebcase/tmpfile v1.0.1/go.mod h1:iErLeG/iqJr8LaQ/gYRv4GXdqssi3jg4iSzvrA06/lw= github.com/calebcase/tmpfile v1.0.1/go.mod h1:iErLeG/iqJr8LaQ/gYRv4GXdqssi3jg4iSzvrA06/lw=
github.com/calebcase/tmpfile v1.0.2-0.20200602150926-3af473ef8439 h1:fqGdSbbWVbQqNCQXd/dyZ7Bl+u8R2X7QCiNzwgyUa/M=
github.com/calebcase/tmpfile v1.0.2-0.20200602150926-3af473ef8439/go.mod h1:iErLeG/iqJr8LaQ/gYRv4GXdqssi3jg4iSzvrA06/lw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheggaaa/pb/v3 v3.0.1 h1:m0BngUk2LuSRYdx4fujDKNRXNDpbNCfptPfVT2m6OJY= github.com/cheggaaa/pb/v3 v3.0.1 h1:m0BngUk2LuSRYdx4fujDKNRXNDpbNCfptPfVT2m6OJY=
@ -621,12 +623,16 @@ storj.io/common v0.0.0-20200616122322-79b46deca70e h1:eAq23qVHALvUhH1PrtHnRPUXo7
storj.io/common v0.0.0-20200616122322-79b46deca70e/go.mod h1:ZSjZI9XJNevOP527K+PL1c68j8w5M4vbHha3V2tYWdQ= storj.io/common v0.0.0-20200616122322-79b46deca70e/go.mod h1:ZSjZI9XJNevOP527K+PL1c68j8w5M4vbHha3V2tYWdQ=
storj.io/common v0.0.0-20200622152042-376f8bec9266 h1:Pmvy8chvf8NsGw91nlrPq/yym1WMranq0SBLh23rhts= storj.io/common v0.0.0-20200622152042-376f8bec9266 h1:Pmvy8chvf8NsGw91nlrPq/yym1WMranq0SBLh23rhts=
storj.io/common v0.0.0-20200622152042-376f8bec9266/go.mod h1:ZSjZI9XJNevOP527K+PL1c68j8w5M4vbHha3V2tYWdQ= storj.io/common v0.0.0-20200622152042-376f8bec9266/go.mod h1:ZSjZI9XJNevOP527K+PL1c68j8w5M4vbHha3V2tYWdQ=
storj.io/common v0.0.0-20200701134427-63fe7147a3f3 h1:+7dtbWpeBeFrYIesoGfhGAPxTTBThwbwmuIwbaQyFo0=
storj.io/common v0.0.0-20200701134427-63fe7147a3f3/go.mod h1:vMAnlNbkgW6i+w/OT1h4X8w6TajOHWAT+SvFHUFCpq0=
storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw= storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw=
storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw= storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw=
storj.io/drpc v0.0.12 h1:4ei1M4cnWlYxcQheX0Dg4+c12zCD+oJqfweVQVWarsA= storj.io/drpc v0.0.12 h1:4ei1M4cnWlYxcQheX0Dg4+c12zCD+oJqfweVQVWarsA=
storj.io/drpc v0.0.12 h1:4ei1M4cnWlYxcQheX0Dg4+c12zCD+oJqfweVQVWarsA= storj.io/drpc v0.0.12 h1:4ei1M4cnWlYxcQheX0Dg4+c12zCD+oJqfweVQVWarsA=
storj.io/drpc v0.0.12/go.mod h1:82nfl+6YwRwF6UG31cEWWUqv/FaKvP5SGqUvoqTxCMA= storj.io/drpc v0.0.12/go.mod h1:82nfl+6YwRwF6UG31cEWWUqv/FaKvP5SGqUvoqTxCMA=
storj.io/drpc v0.0.12/go.mod h1:82nfl+6YwRwF6UG31cEWWUqv/FaKvP5SGqUvoqTxCMA= storj.io/drpc v0.0.12/go.mod h1:82nfl+6YwRwF6UG31cEWWUqv/FaKvP5SGqUvoqTxCMA=
storj.io/drpc v0.0.13 h1:EDR3WiwVcIHtg+8M5vqBFmUAuJvmM2erVHIfqPPSAoc=
storj.io/drpc v0.0.13/go.mod h1:82nfl+6YwRwF6UG31cEWWUqv/FaKvP5SGqUvoqTxCMA=
storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b h1:Bbg9JCtY6l3HrDxs3BXzT2UYnYCBLqNi6i84Y8QIPUs= storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b h1:Bbg9JCtY6l3HrDxs3BXzT2UYnYCBLqNi6i84Y8QIPUs=
storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b/go.mod h1:gj4vuCeyCRjRmH8LIrgoyU9Dc9uR6H+/GcDUXmTbf80= storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b/go.mod h1:gj4vuCeyCRjRmH8LIrgoyU9Dc9uR6H+/GcDUXmTbf80=
storj.io/private v0.0.0-20200605221229-3236fe879ab3 h1:kUn1+iJmBwBTJopuNlN3daKAXLNe1u3F/cGDq0o3sak= storj.io/private v0.0.0-20200605221229-3236fe879ab3 h1:kUn1+iJmBwBTJopuNlN3daKAXLNe1u3F/cGDq0o3sak=

View File

@ -52,7 +52,7 @@ func (e *Endpoint) GetPayStub(ctx context.Context, req *pb.GetHeldAmountRequest)
node, err := e.overlay.Get(ctx, peer.ID) node, err := e.overlay.Get(ctx, peer.ID)
if err != nil { if err != nil {
if overlay.ErrNodeNotFound.Has(err) { if overlay.ErrNodeNotFound.Has(err) {
return nil, rpcstatus.Error(rpcstatus.PermissionDenied, err.Error()) return nil, rpcstatus.Error(rpcstatus.NotFound, err.Error())
} }
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error()) return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
@ -64,7 +64,7 @@ func (e *Endpoint) GetPayStub(ctx context.Context, req *pb.GetHeldAmountRequest)
if ErrNoDataForPeriod.Has(err) { if ErrNoDataForPeriod.Has(err) {
return nil, rpcstatus.Error(rpcstatus.OutOfRange, err.Error()) return nil, rpcstatus.Error(rpcstatus.OutOfRange, err.Error())
} }
return nil, err return nil, Error.Wrap(err)
} }
periodTime, err := date.PeriodToTime(stub.Period) periodTime, err := date.PeriodToTime(stub.Period)
@ -107,7 +107,7 @@ func (e *Endpoint) GetAllPaystubs(ctx context.Context, req *pb.GetAllPaystubsReq
node, err := e.overlay.Get(ctx, peer.ID) node, err := e.overlay.Get(ctx, peer.ID)
if err != nil { if err != nil {
if overlay.ErrNodeNotFound.Has(err) { if overlay.ErrNodeNotFound.Has(err) {
return nil, rpcstatus.Error(rpcstatus.PermissionDenied, err.Error()) return nil, rpcstatus.Error(rpcstatus.NotFound, err.Error())
} }
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error()) return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
@ -118,7 +118,7 @@ func (e *Endpoint) GetAllPaystubs(ctx context.Context, req *pb.GetAllPaystubsReq
if ErrNoDataForPeriod.Has(err) { if ErrNoDataForPeriod.Has(err) {
return nil, rpcstatus.Error(rpcstatus.OutOfRange, err.Error()) return nil, rpcstatus.Error(rpcstatus.OutOfRange, err.Error())
} }
return nil, err return nil, Error.Wrap(err)
} }
var paystubs []*pb.GetHeldAmountResponse var paystubs []*pb.GetHeldAmountResponse
@ -130,7 +130,7 @@ func (e *Endpoint) GetAllPaystubs(ctx context.Context, req *pb.GetAllPaystubsReq
for i := 0; i < len(stubs); i++ { for i := 0; i < len(stubs); i++ {
period, err := date.PeriodToTime(stubs[i].Period) period, err := date.PeriodToTime(stubs[i].Period)
if err != nil { if err != nil {
return nil, err return nil, Error.Wrap(err)
} }
heldAmountResponse := pb.GetHeldAmountResponse{ heldAmountResponse := pb.GetHeldAmountResponse{
@ -162,3 +162,97 @@ func (e *Endpoint) GetAllPaystubs(ctx context.Context, req *pb.GetAllPaystubsReq
return &response, nil return &response, nil
} }
// GetPayment sends node payment data for client node.
func (e *Endpoint) GetPayment(ctx context.Context, req *pb.GetPaymentRequest) (_ *pb.GetPaymentResponse, err error) {
defer mon.Task()(&ctx)(&err)
peer, err := identity.PeerIdentityFromContext(ctx)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.Unauthenticated, err.Error())
}
node, err := e.overlay.Get(ctx, peer.ID)
if err != nil {
if overlay.ErrNodeNotFound.Has(err) {
return nil, rpcstatus.Error(rpcstatus.NotFound, err.Error())
}
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
payment, err := e.service.GetPayment(ctx, node.Id, req.Period.String())
if err != nil {
if ErrNoDataForPeriod.Has(err) {
return nil, rpcstatus.Error(rpcstatus.OutOfRange, err.Error())
}
return nil, Error.Wrap(err)
}
timePeriod, err := date.PeriodToTime(payment.Period)
if err != nil {
return nil, Error.Wrap(err)
}
return &pb.GetPaymentResponse{
NodeId: payment.NodeID,
CreatedAt: payment.Created,
Period: timePeriod,
Amount: payment.Amount,
Receipt: payment.Receipt,
Notes: payment.Notes,
Id: payment.ID,
}, nil
}
// GetAllPayments sends all payments to node.
func (e *Endpoint) GetAllPayments(ctx context.Context, req *pb.GetAllPaymentsRequest) (_ *pb.GetAllPaymentsResponse, err error) {
defer mon.Task()(&ctx)(&err)
peer, err := identity.PeerIdentityFromContext(ctx)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.Unauthenticated, err.Error())
}
node, err := e.overlay.Get(ctx, peer.ID)
if err != nil {
if overlay.ErrNodeNotFound.Has(err) {
return nil, rpcstatus.Error(rpcstatus.NotFound, err.Error())
}
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
allPayments, err := e.service.GetAllPayments(ctx, node.Id)
if err != nil {
if ErrNoDataForPeriod.Has(err) {
return nil, rpcstatus.Error(rpcstatus.OutOfRange, err.Error())
}
return nil, Error.Wrap(err)
}
var payments []*pb.GetPaymentResponse
response := pb.GetAllPaymentsResponse{
Payment: payments,
}
for i := 0; i < len(allPayments); i++ {
period, err := date.PeriodToTime(allPayments[i].Period)
if err != nil {
return nil, Error.Wrap(err)
}
paymentResponse := pb.GetPaymentResponse{
NodeId: allPayments[i].NodeID,
CreatedAt: allPayments[i].Created,
Period: period,
Amount: allPayments[i].Amount,
Receipt: allPayments[i].Receipt,
Notes: allPayments[i].Notes,
Id: allPayments[i].ID,
}
response.Payment = append(response.Payment, &paymentResponse)
}
return &response, nil
}

View File

@ -23,11 +23,20 @@ type DB interface {
GetAllPaystubs(ctx context.Context, nodeID storj.NodeID) ([]PayStub, error) GetAllPaystubs(ctx context.Context, nodeID storj.NodeID) ([]PayStub, error)
// CreatePaystub insert paystub into db. // CreatePaystub insert paystub into db.
CreatePaystub(ctx context.Context, stub PayStub) (err error) CreatePaystub(ctx context.Context, stub PayStub) (err error)
// GetPayment return storagenode payment by nodeID and period.
GetPayment(ctx context.Context, nodeID storj.NodeID, period string) (StoragenodePayment, error)
// CreatePayment insert payment into db.
CreatePayment(ctx context.Context, payment StoragenodePayment) (err error)
// GetAllPayments return all payments by nodeID.
GetAllPayments(ctx context.Context, nodeID storj.NodeID) ([]StoragenodePayment, error)
} }
// ErrNoDataForPeriod represents errors from the heldamount database. // ErrNoDataForPeriod represents errors from the heldamount database.
var ErrNoDataForPeriod = errs.Class("no payStub/payments for period error") var ErrNoDataForPeriod = errs.Class("no payStub/payments for period error")
// Error is the default error class for heldamount package.
var Error = errs.Class("heldamount")
// PayStub is an entity that holds held amount of cash that will be paid to storagenode operator after some period. // PayStub is an entity that holds held amount of cash that will be paid to storagenode operator after some period.
type PayStub struct { type PayStub struct {
Period string `json:"period"` Period string `json:"period"`
@ -53,6 +62,17 @@ type PayStub struct {
Paid int64 `json:"paid"` Paid int64 `json:"paid"`
} }
// StoragenodePayment is an entity that holds payment to storagenode operator parameters.
type StoragenodePayment struct {
ID int64 `json:"id"`
Created time.Time `json:"created"`
NodeID storj.NodeID `json:"nodeId"`
Period string `json:"period"`
Amount int64 `json:"amount"`
Receipt string `json:"receipt"`
Notes string `json:"notes"`
}
// Service is used to store and handle node paystub information // Service is used to store and handle node paystub information
// //
// architecture: Service // architecture: Service
@ -73,7 +93,7 @@ func NewService(log *zap.Logger, db DB) *Service {
func (service *Service) GetPayStub(ctx context.Context, nodeID storj.NodeID, period string) (PayStub, error) { func (service *Service) GetPayStub(ctx context.Context, nodeID storj.NodeID, period string) (PayStub, error) {
payStub, err := service.db.GetPaystub(ctx, nodeID, period) payStub, err := service.db.GetPaystub(ctx, nodeID, period)
if err != nil { if err != nil {
return PayStub{}, err return PayStub{}, Error.Wrap(err)
} }
return payStub, nil return payStub, nil
@ -83,8 +103,28 @@ func (service *Service) GetPayStub(ctx context.Context, nodeID storj.NodeID, per
func (service *Service) GetAllPaystubs(ctx context.Context, nodeID storj.NodeID) ([]PayStub, error) { func (service *Service) GetAllPaystubs(ctx context.Context, nodeID storj.NodeID) ([]PayStub, error) {
payStubs, err := service.db.GetAllPaystubs(ctx, nodeID) payStubs, err := service.db.GetAllPaystubs(ctx, nodeID)
if err != nil { if err != nil {
return []PayStub{}, err return []PayStub{}, Error.Wrap(err)
} }
return payStubs, nil return payStubs, nil
} }
// GetPayment returns storagenode payment data by nodeID and period.
func (service *Service) GetPayment(ctx context.Context, nodeID storj.NodeID, period string) (StoragenodePayment, error) {
payment, err := service.db.GetPayment(ctx, nodeID, period)
if err != nil {
return StoragenodePayment{}, Error.Wrap(err)
}
return payment, nil
}
// GetAllPayments returns all payments by nodeID.
func (service *Service) GetAllPayments(ctx context.Context, nodeID storj.NodeID) ([]StoragenodePayment, error) {
payments, err := service.db.GetAllPayments(ctx, nodeID)
if err != nil {
return nil, Error.Wrap(err)
}
return payments, nil
}

View File

@ -205,5 +205,36 @@ func TestHeldAmountDB(t *testing.T) {
} }
} }
}) })
payment := heldamount.StoragenodePayment{
ID: 1,
Created: time.Now().UTC(),
NodeID: NodeID,
Period: "2020-01",
Amount: 123,
Receipt: "receipt",
Notes: "notes",
}
t.Run("Test StorePayment", func(t *testing.T) {
err := heldAmount.CreatePayment(ctx, payment)
assert.NoError(t, err)
})
t.Run("Test GetPayment", func(t *testing.T) {
paym, err := heldAmount.GetPayment(ctx, NodeID, period)
assert.NoError(t, err)
assert.Equal(t, paym.NodeID, payment.NodeID)
assert.Equal(t, paym.Period, payment.Period)
assert.Equal(t, paym.Amount, payment.Amount)
assert.Equal(t, paym.Notes, payment.Notes)
assert.Equal(t, paym.Receipt, payment.Receipt)
paym, err = heldAmount.GetPayment(ctx, NodeID, "")
assert.Error(t, err)
paym, err = heldAmount.GetPayment(ctx, storj.NodeID{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, period)
assert.Error(t, err)
})
}) })
} }

View File

@ -135,3 +135,78 @@ func (paystubs *paymentStubs) CreatePaystub(ctx context.Context, stub heldamount
dbx.StoragenodePaystub_Paid(stub.Paid), dbx.StoragenodePaystub_Paid(stub.Paid),
) )
} }
// GetPayment returns payment by nodeID and period.
func (paystubs *paymentStubs) GetPayment(ctx context.Context, nodeID storj.NodeID, period string) (payment heldamount.StoragenodePayment, err error) {
query := `SELECT * FROM storagenode_payments WHERE node_id = $1 AND period = $2;`
row := paystubs.db.QueryRowContext(ctx, query, nodeID, period)
err = row.Scan(
&payment.ID,
&payment.Created,
&payment.NodeID,
&payment.Period,
&payment.Amount,
&payment.Receipt,
&payment.Notes,
)
if err != nil {
if sql.ErrNoRows == err {
return heldamount.StoragenodePayment{}, heldamount.ErrNoDataForPeriod.Wrap(err)
}
return heldamount.StoragenodePayment{}, Error.Wrap(err)
}
return payment, nil
}
// CreatePayment inserts storagenode_payment into database.
func (paystubs *paymentStubs) CreatePayment(ctx context.Context, payment heldamount.StoragenodePayment) (err error) {
return paystubs.db.CreateNoReturn_StoragenodePayment(
ctx,
dbx.StoragenodePayment_NodeId(payment.NodeID[:]),
dbx.StoragenodePayment_Period(payment.Period),
dbx.StoragenodePayment_Amount(payment.Amount),
dbx.StoragenodePayment_Create_Fields{
Receipt: dbx.StoragenodePayment_Receipt(payment.Receipt),
Notes: dbx.StoragenodePayment_Notes(payment.Notes),
},
)
}
// GetAllPayments return all payments by nodeID.
func (paystubs *paymentStubs) GetAllPayments(ctx context.Context, nodeID storj.NodeID) (payments []heldamount.StoragenodePayment, err error) {
query := `SELECT * FROM storagenode_payments WHERE node_id = $1;`
rows, err := paystubs.db.QueryContext(ctx, query, nodeID)
if err != nil {
return nil, Error.Wrap(err)
}
defer func() {
err = errs.Combine(err, Error.Wrap(rows.Close()))
}()
for rows.Next() {
payment := heldamount.StoragenodePayment{}
err = rows.Scan(
&payment.ID,
&payment.Created,
&payment.NodeID,
&payment.Period,
&payment.Amount,
&payment.Receipt,
&payment.Notes,
)
if err = rows.Err(); err != nil {
return nil, Error.Wrap(err)
}
payments = append(payments, payment)
}
return payments, Error.Wrap(rows.Err())
}