multinode/console: held amount summary

Change-Id: Ia800748343e363d930ce0a0b9ab286b5abdc96af
This commit is contained in:
Yaroslav Vorobiov 2021-04-22 21:50:42 +03:00
parent 0ef537a685
commit 23f9beb635
17 changed files with 994 additions and 160 deletions

View File

@ -12,6 +12,7 @@ import (
"go.uber.org/zap"
"storj.io/common/storj"
"storj.io/storj/multinode/nodes"
"storj.io/storj/multinode/payouts"
)
@ -393,6 +394,43 @@ func (controller *Payouts) PaystubPeriod(w http.ResponseWriter, r *http.Request)
}
}
// HeldAmountSummary handles retrieving held amount history for a node.
func (controller *Payouts) HeldAmountSummary(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
vars := mux.Vars(r)
idString, ok := vars["nodeID"]
if !ok {
controller.serveError(w, http.StatusBadRequest, ErrPayouts.New("node id segment parameter is missing"))
return
}
nodeID, err := storj.NodeIDFromString(idString)
if err != nil {
controller.serveError(w, http.StatusBadRequest, ErrPayouts.Wrap(err))
return
}
heldSummary, err := controller.service.HeldAmountSummary(ctx, nodeID)
if err != nil {
if nodes.ErrNoNode.Has(err) {
controller.serveError(w, http.StatusNotFound, ErrPayouts.Wrap(err))
return
}
controller.log.Error("held amount history internal error", zap.Error(err))
controller.serveError(w, http.StatusInternalServerError, ErrPayouts.Wrap(err))
return
}
if err = json.NewEncoder(w).Encode(heldSummary); err != nil {
controller.log.Error("failed to write json response", zap.Error(err))
return
}
}
// serveError set http statuses and send json error.
func (controller *Payouts) serveError(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)

View File

@ -86,6 +86,7 @@ func NewServer(log *zap.Logger, config Config, nodes *nodes.Service, payouts *pa
payoutsRouter.HandleFunc("/satellite/{id}/paystub/{nodeID}", payoutsController.SatellitePaystub).Methods(http.MethodGet)
payoutsRouter.HandleFunc("/paystub/{period}/{nodeID}", payoutsController.PaystubPeriod).Methods(http.MethodGet)
payoutsRouter.HandleFunc("/paystub/{nodeID}", payoutsController.Paystub).Methods(http.MethodGet)
payoutsRouter.HandleFunc("/held-amounts/{nodeID}", payoutsController.HeldAmountSummary).Methods(http.MethodGet)
if server.config.StaticDir != "" {
router.PathPrefix("/static/").Handler(http.StripPrefix("/static", fs))

View File

@ -13,6 +13,28 @@ type SatelliteSummary struct {
Earned int64 `json:"earned"`
}
// HeldAmountHistory contains held amount history of particular satellite.
type HeldAmountHistory struct {
SatelliteID storj.NodeID `json:"satelliteId"`
HeldAmounts []HeldAmount `json:"heldAmounts"`
}
// HeldAmount contains amount held for period.
type HeldAmount struct {
Period string `json:"period"`
Amount int64 `json:"amount"`
}
// HeldAmountSummary contains held amount summary for first 3 quarters.
type HeldAmountSummary struct {
SatelliteID storj.NodeID `json:"satelliteId"`
SatelliteURL storj.NodeURL `json:"satelliteUrl"`
FirstQuarter int64 `json:"firstQuarter"`
SecondQuarter int64 `json:"secondQuarter"`
ThirdQuarter int64 `json:"thirdQuarter"`
PeriodCount int `json:"periodCount"`
}
// NodeSummary contains node's payout information.
type NodeSummary struct {
NodeID storj.NodeID `json:"nodeId"`

View File

@ -12,6 +12,7 @@ import (
"storj.io/common/rpc"
"storj.io/common/storj"
"storj.io/drpc"
"storj.io/storj/multinode/nodes"
"storj.io/storj/private/multinodepb"
)
@ -349,6 +350,119 @@ func (service *Service) Expectations(ctx context.Context) (_ Expectations, err e
return expectations, nil
}
// HeldAmountSummary retrieves held amount history summary for a particular node.
func (service *Service) HeldAmountSummary(ctx context.Context, nodeID storj.NodeID) (_ []HeldAmountSummary, err error) {
defer mon.Task()(&ctx)(&err)
node, err := service.nodes.Get(ctx, nodeID)
if err != nil {
return nil, Error.Wrap(err)
}
conn, err := service.dialer.DialNodeURL(ctx, storj.NodeURL{
ID: node.ID,
Address: node.PublicAddress,
})
if err != nil {
return nil, Error.Wrap(err)
}
defer func() {
err = errs.Combine(err, conn.Close())
}()
nodeClient := multinodepb.NewDRPCNodeClient(conn)
header := &multinodepb.RequestHeader{
ApiKey: node.APISecret,
}
trusted, err := nodeClient.TrustedSatellites(ctx, &multinodepb.TrustedSatellitesRequest{
Header: header,
})
if err != nil {
return nil, Error.Wrap(err)
}
history, err := service.heldAmountHistory(ctx, node, conn)
if err != nil {
return nil, Error.Wrap(err)
}
trustedSatellites := trusted.GetTrustedSatellites()
var summary []HeldAmountSummary
for _, satelliteHistory := range history {
satelliteSummary := HeldAmountSummary{
SatelliteID: satelliteHistory.SatelliteID,
}
for _, trustedSatellite := range trustedSatellites {
if satelliteSummary.SatelliteID.Compare(trustedSatellite.NodeId) == 0 {
satelliteSummary.SatelliteURL = storj.NodeURL{
ID: trustedSatellite.NodeId,
Address: trustedSatellite.GetAddress(),
}
}
}
if len(satelliteHistory.HeldAmounts) == 0 {
summary = append(summary, satelliteSummary)
continue
}
satelliteSummary.PeriodCount = len(satelliteHistory.HeldAmounts)
for i, heldAmount := range satelliteHistory.HeldAmounts {
switch i {
case 1, 2, 3:
satelliteSummary.FirstQuarter += heldAmount.Amount
case 4, 5, 6:
satelliteSummary.SecondQuarter += heldAmount.Amount
case 7, 8, 9:
satelliteSummary.ThirdQuarter += heldAmount.Amount
}
}
summary = append(summary, satelliteSummary)
}
return summary, nil
}
// heldAmountHistory retrieves held amount history for a particular node.
func (service *Service) heldAmountHistory(ctx context.Context, node nodes.Node, conn drpc.Conn) (_ []HeldAmountHistory, err error) {
defer mon.Task()(&ctx)(&err)
payoutClient := multinodepb.NewDRPCPayoutClient(conn)
header := &multinodepb.RequestHeader{
ApiKey: node.APISecret,
}
resp, err := payoutClient.HeldAmountHistory(ctx, &multinodepb.HeldAmountHistoryRequest{
Header: header,
})
if err != nil {
return nil, err
}
var history []HeldAmountHistory
for _, pbHistory := range resp.GetHistory() {
var heldAmounts []HeldAmount
for _, pbHeldAmount := range pbHistory.GetHeldAmounts() {
heldAmounts = append(heldAmounts, HeldAmount{
Period: pbHeldAmount.GetPeriod(),
Amount: pbHeldAmount.GetAmount(),
})
}
history = append(history, HeldAmountHistory{
SatelliteID: pbHistory.SatelliteId,
HeldAmounts: heldAmounts,
})
}
return history, nil
}
// nodeExpectations retrieves data from a single node.
func (service *Service) nodeExpectations(ctx context.Context, node nodes.Node) (_ Expectations, err error) {
conn, err := service.dialer.DialNodeURL(ctx, storj.NodeURL{

View File

@ -33,6 +33,7 @@ import "google/protobuf/descriptor.proto";
option java_package = "com.google.protobuf";
option java_outer_classname = "GoGoProtos";
option go_package = "storj.io/storj/private/multinodepb";
extend google.protobuf.EnumOptions {
optional bool goproto_enum_prefix = 62001;

View File

@ -1917,6 +1917,171 @@ func (m *Paystub) GetDistributed() int64 {
return 0
}
type HeldAmountHistoryRequest struct {
Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HeldAmountHistoryRequest) Reset() { *m = HeldAmountHistoryRequest{} }
func (m *HeldAmountHistoryRequest) String() string { return proto.CompactTextString(m) }
func (*HeldAmountHistoryRequest) ProtoMessage() {}
func (*HeldAmountHistoryRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_9a45fd79b06f3a1b, []int{42}
}
func (m *HeldAmountHistoryRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HeldAmountHistoryRequest.Unmarshal(m, b)
}
func (m *HeldAmountHistoryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HeldAmountHistoryRequest.Marshal(b, m, deterministic)
}
func (m *HeldAmountHistoryRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_HeldAmountHistoryRequest.Merge(m, src)
}
func (m *HeldAmountHistoryRequest) XXX_Size() int {
return xxx_messageInfo_HeldAmountHistoryRequest.Size(m)
}
func (m *HeldAmountHistoryRequest) XXX_DiscardUnknown() {
xxx_messageInfo_HeldAmountHistoryRequest.DiscardUnknown(m)
}
var xxx_messageInfo_HeldAmountHistoryRequest proto.InternalMessageInfo
func (m *HeldAmountHistoryRequest) GetHeader() *RequestHeader {
if m != nil {
return m.Header
}
return nil
}
type HeldAmountHistoryResponse struct {
History []*HeldAmountHistoryResponse_HeldAmountHistory `protobuf:"bytes,1,rep,name=history,proto3" json:"history,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HeldAmountHistoryResponse) Reset() { *m = HeldAmountHistoryResponse{} }
func (m *HeldAmountHistoryResponse) String() string { return proto.CompactTextString(m) }
func (*HeldAmountHistoryResponse) ProtoMessage() {}
func (*HeldAmountHistoryResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_9a45fd79b06f3a1b, []int{43}
}
func (m *HeldAmountHistoryResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HeldAmountHistoryResponse.Unmarshal(m, b)
}
func (m *HeldAmountHistoryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HeldAmountHistoryResponse.Marshal(b, m, deterministic)
}
func (m *HeldAmountHistoryResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_HeldAmountHistoryResponse.Merge(m, src)
}
func (m *HeldAmountHistoryResponse) XXX_Size() int {
return xxx_messageInfo_HeldAmountHistoryResponse.Size(m)
}
func (m *HeldAmountHistoryResponse) XXX_DiscardUnknown() {
xxx_messageInfo_HeldAmountHistoryResponse.DiscardUnknown(m)
}
var xxx_messageInfo_HeldAmountHistoryResponse proto.InternalMessageInfo
func (m *HeldAmountHistoryResponse) GetHistory() []*HeldAmountHistoryResponse_HeldAmountHistory {
if m != nil {
return m.History
}
return nil
}
type HeldAmountHistoryResponse_HeldAmount struct {
Period string `protobuf:"bytes,1,opt,name=period,proto3" json:"period,omitempty"`
Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HeldAmountHistoryResponse_HeldAmount) Reset() { *m = HeldAmountHistoryResponse_HeldAmount{} }
func (m *HeldAmountHistoryResponse_HeldAmount) String() string { return proto.CompactTextString(m) }
func (*HeldAmountHistoryResponse_HeldAmount) ProtoMessage() {}
func (*HeldAmountHistoryResponse_HeldAmount) Descriptor() ([]byte, []int) {
return fileDescriptor_9a45fd79b06f3a1b, []int{43, 0}
}
func (m *HeldAmountHistoryResponse_HeldAmount) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount.Unmarshal(m, b)
}
func (m *HeldAmountHistoryResponse_HeldAmount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount.Marshal(b, m, deterministic)
}
func (m *HeldAmountHistoryResponse_HeldAmount) XXX_Merge(src proto.Message) {
xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount.Merge(m, src)
}
func (m *HeldAmountHistoryResponse_HeldAmount) XXX_Size() int {
return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount.Size(m)
}
func (m *HeldAmountHistoryResponse_HeldAmount) XXX_DiscardUnknown() {
xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount.DiscardUnknown(m)
}
var xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount proto.InternalMessageInfo
func (m *HeldAmountHistoryResponse_HeldAmount) GetPeriod() string {
if m != nil {
return m.Period
}
return ""
}
func (m *HeldAmountHistoryResponse_HeldAmount) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
type HeldAmountHistoryResponse_HeldAmountHistory struct {
SatelliteId NodeID `protobuf:"bytes,1,opt,name=satellite_id,json=satelliteId,proto3,customtype=NodeID" json:"satellite_id"`
HeldAmounts []*HeldAmountHistoryResponse_HeldAmount `protobuf:"bytes,2,rep,name=held_amounts,json=heldAmounts,proto3" json:"held_amounts,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) Reset() {
*m = HeldAmountHistoryResponse_HeldAmountHistory{}
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) String() string {
return proto.CompactTextString(m)
}
func (*HeldAmountHistoryResponse_HeldAmountHistory) ProtoMessage() {}
func (*HeldAmountHistoryResponse_HeldAmountHistory) Descriptor() ([]byte, []int) {
return fileDescriptor_9a45fd79b06f3a1b, []int{43, 1}
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory.Unmarshal(m, b)
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory.Marshal(b, m, deterministic)
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) XXX_Merge(src proto.Message) {
xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory.Merge(m, src)
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) XXX_Size() int {
return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory.Size(m)
}
func (m *HeldAmountHistoryResponse_HeldAmountHistory) XXX_DiscardUnknown() {
xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory.DiscardUnknown(m)
}
var xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory proto.InternalMessageInfo
func (m *HeldAmountHistoryResponse_HeldAmountHistory) GetHeldAmounts() []*HeldAmountHistoryResponse_HeldAmount {
if m != nil {
return m.HeldAmounts
}
return nil
}
func init() {
proto.RegisterType((*RequestHeader)(nil), "multinode.RequestHeader")
proto.RegisterType((*DiskSpaceRequest)(nil), "multinode.DiskSpaceRequest")
@ -1963,106 +2128,116 @@ func init() {
proto.RegisterType((*SatellitePeriodPaystubResponse)(nil), "multinode.SatellitePeriodPaystubResponse")
proto.RegisterType((*PayoutInfo)(nil), "multinode.PayoutInfo")
proto.RegisterType((*Paystub)(nil), "multinode.Paystub")
proto.RegisterType((*HeldAmountHistoryRequest)(nil), "multinode.HeldAmountHistoryRequest")
proto.RegisterType((*HeldAmountHistoryResponse)(nil), "multinode.HeldAmountHistoryResponse")
proto.RegisterType((*HeldAmountHistoryResponse_HeldAmount)(nil), "multinode.HeldAmountHistoryResponse.HeldAmount")
proto.RegisterType((*HeldAmountHistoryResponse_HeldAmountHistory)(nil), "multinode.HeldAmountHistoryResponse.HeldAmountHistory")
}
func init() { proto.RegisterFile("multinode.proto", fileDescriptor_9a45fd79b06f3a1b) }
var fileDescriptor_9a45fd79b06f3a1b = []byte{
// 1524 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xdf, 0x72, 0xdb, 0x44,
0x17, 0xff, 0x9c, 0x3f, 0x76, 0x7c, 0xec, 0xc4, 0xc9, 0x7e, 0x49, 0xab, 0xa8, 0x49, 0x9d, 0x4f,
0xcd, 0x97, 0xa6, 0xb4, 0x75, 0x20, 0x65, 0x98, 0x61, 0x06, 0x86, 0x26, 0x34, 0x6d, 0x32, 0xa4,
0x6d, 0xaa, 0xa4, 0x1d, 0xa6, 0x30, 0x35, 0x1b, 0x6b, 0xe3, 0x88, 0xca, 0x92, 0xd0, 0xae, 0x03,
0xb9, 0xe1, 0x92, 0x6b, 0x1e, 0x80, 0x77, 0x61, 0xb8, 0x61, 0x78, 0x06, 0x2e, 0xca, 0x1b, 0x30,
0xc3, 0x15, 0xb7, 0xcc, 0xfe, 0x91, 0x2c, 0xd9, 0x6b, 0x37, 0xd8, 0x4c, 0xb9, 0xd3, 0x9e, 0xf3,
0xdb, 0xdf, 0x39, 0x67, 0xf7, 0xec, 0xee, 0x39, 0x82, 0x4a, 0xab, 0xed, 0x31, 0xd7, 0x0f, 0x1c,
0x52, 0x0b, 0xa3, 0x80, 0x05, 0xa8, 0x98, 0x08, 0x4c, 0x68, 0x06, 0xcd, 0x40, 0x8a, 0xcd, 0x6a,
0x33, 0x08, 0x9a, 0x1e, 0xd9, 0x10, 0xa3, 0xe3, 0xf6, 0xc9, 0x06, 0x73, 0x5b, 0x84, 0x32, 0xdc,
0x0a, 0x25, 0xc0, 0x5a, 0x87, 0x69, 0x9b, 0x7c, 0xd5, 0x26, 0x94, 0xed, 0x12, 0xec, 0x90, 0x08,
0x5d, 0x86, 0x02, 0x0e, 0xdd, 0xfa, 0x4b, 0x72, 0x6e, 0xe4, 0x56, 0x72, 0xeb, 0x65, 0x3b, 0x8f,
0x43, 0xf7, 0x13, 0x72, 0x6e, 0xdd, 0x83, 0xd9, 0x7b, 0x2e, 0x7d, 0x79, 0x18, 0xe2, 0x06, 0x51,
0x53, 0xd0, 0xdb, 0x90, 0x3f, 0x15, 0xd3, 0x04, 0xb6, 0xb4, 0x69, 0xd4, 0x3a, 0x7e, 0x65, 0x68,
0x6d, 0x85, 0xb3, 0x7e, 0xcc, 0xc1, 0x5c, 0x8a, 0x86, 0x86, 0x81, 0x4f, 0x09, 0x5a, 0x82, 0x22,
0xf6, 0xbc, 0xa0, 0x81, 0x19, 0x71, 0x04, 0xd5, 0xb8, 0xdd, 0x11, 0xa0, 0x2a, 0x94, 0xda, 0x94,
0x38, 0xf5, 0xd0, 0x25, 0x0d, 0x42, 0x8d, 0x31, 0xa1, 0x07, 0x2e, 0x3a, 0x10, 0x12, 0xb4, 0x0c,
0x62, 0x54, 0x67, 0x11, 0xa6, 0xa7, 0xc6, 0xb8, 0x9c, 0xcf, 0x25, 0x47, 0x5c, 0x80, 0x10, 0x4c,
0x9c, 0x44, 0x84, 0x18, 0x13, 0x42, 0x21, 0xbe, 0x85, 0xc5, 0x33, 0xec, 0x7a, 0xf8, 0xd8, 0x23,
0xc6, 0xa4, 0xb2, 0x18, 0x0b, 0x90, 0x09, 0x53, 0xc1, 0x19, 0x89, 0x38, 0x85, 0x91, 0x17, 0xca,
0x64, 0x6c, 0x1d, 0xc0, 0xd2, 0x36, 0xf6, 0x9d, 0xaf, 0x5d, 0x87, 0x9d, 0x3e, 0x0c, 0x7c, 0x76,
0x7a, 0xd8, 0x6e, 0xb5, 0x70, 0x74, 0x3e, 0xfc, 0x9a, 0xdc, 0x81, 0xe5, 0x3e, 0x8c, 0x6a, 0x79,
0x10, 0x4c, 0x08, 0x57, 0xe4, 0xca, 0x88, 0x6f, 0x6b, 0x1b, 0x66, 0x9e, 0x91, 0x88, 0xba, 0x81,
0x3f, 0xbc, 0xe1, 0x9b, 0x50, 0x49, 0x38, 0x94, 0x29, 0x03, 0x0a, 0x67, 0x52, 0x24, 0x58, 0x8a,
0x76, 0x3c, 0xb4, 0xee, 0x03, 0xda, 0xc7, 0x94, 0x7d, 0x1c, 0xf8, 0x0c, 0x37, 0xd8, 0xf0, 0x46,
0x5f, 0xc0, 0x7f, 0x33, 0x3c, 0xca, 0xf0, 0x03, 0x28, 0x7b, 0x98, 0xb2, 0x7a, 0x43, 0xca, 0x15,
0x9d, 0x59, 0x93, 0x09, 0x5c, 0x8b, 0x13, 0xb8, 0x76, 0x14, 0x27, 0xf0, 0xf6, 0xd4, 0x2f, 0xaf,
0xaa, 0xff, 0xf9, 0xfe, 0xb7, 0x6a, 0xce, 0x2e, 0x79, 0x1d, 0x42, 0xeb, 0x1b, 0x98, 0xb3, 0x49,
0xd8, 0x66, 0x98, 0x8d, 0xb2, 0x36, 0xe8, 0x1d, 0x28, 0x53, 0xcc, 0x88, 0xe7, 0xb9, 0x8c, 0xd4,
0x5d, 0x47, 0x64, 0x5d, 0x79, 0x7b, 0x86, 0xdb, 0xfc, 0xf5, 0x55, 0x35, 0xff, 0x28, 0x70, 0xc8,
0xde, 0x3d, 0xbb, 0x94, 0x60, 0xf6, 0x1c, 0xeb, 0xcf, 0x1c, 0xa0, 0xb4, 0x69, 0x15, 0xd9, 0x07,
0x90, 0x0f, 0x7c, 0xcf, 0xf5, 0x89, 0xb2, 0xbd, 0x9a, 0xb1, 0xdd, 0x0d, 0xaf, 0x3d, 0x16, 0x58,
0x5b, 0xcd, 0x41, 0xef, 0xc3, 0x24, 0x6e, 0x3b, 0x2e, 0x13, 0x0e, 0x94, 0x36, 0xaf, 0x0d, 0x9e,
0xbc, 0xc5, 0xa1, 0xb6, 0x9c, 0x61, 0x5e, 0x85, 0xbc, 0x24, 0x43, 0xf3, 0x30, 0x49, 0x1b, 0x41,
0x24, 0x3d, 0xc8, 0xd9, 0x72, 0x60, 0xee, 0xc2, 0xa4, 0xc0, 0xeb, 0xd5, 0xe8, 0x06, 0xcc, 0xd2,
0x36, 0x0d, 0x89, 0xcf, 0xb7, 0xbf, 0x2e, 0x01, 0x63, 0x02, 0x50, 0xe9, 0xc8, 0x0f, 0xb9, 0xd8,
0xda, 0x07, 0xe3, 0x28, 0x6a, 0x53, 0x46, 0x9c, 0xc3, 0x78, 0x3d, 0xe8, 0xf0, 0x19, 0xf2, 0x73,
0x0e, 0x16, 0x35, 0x74, 0x6a, 0x39, 0x3f, 0x03, 0xc4, 0xa4, 0xb2, 0x9e, 0x2c, 0x3e, 0x35, 0x72,
0x2b, 0xe3, 0xeb, 0xa5, 0xcd, 0x5b, 0x29, 0xee, 0xbe, 0x0c, 0x35, 0xbe, 0x77, 0x4f, 0xed, 0x7d,
0x7b, 0x8e, 0x75, 0x43, 0xcc, 0x7d, 0x28, 0x28, 0x2d, 0xba, 0x0e, 0x05, 0xce, 0xc3, 0xf7, 0x3e,
0xa7, 0xdd, 0xfb, 0x3c, 0x57, 0xef, 0x39, 0xfc, 0xc8, 0x60, 0xc7, 0x89, 0x08, 0x95, 0x57, 0x53,
0xd1, 0x8e, 0x87, 0xd6, 0x77, 0x39, 0xa8, 0xee, 0x50, 0xe6, 0xb6, 0xf8, 0x35, 0x76, 0x80, 0xcf,
0x83, 0x36, 0x4b, 0x6c, 0xbd, 0xd1, 0xcc, 0x7c, 0x02, 0x2b, 0xfd, 0xfd, 0x50, 0xeb, 0x7a, 0x1b,
0x10, 0x89, 0x31, 0x75, 0x82, 0x23, 0xdf, 0xf5, 0x9b, 0x54, 0x5d, 0x39, 0x73, 0x89, 0x66, 0x47,
0x29, 0xac, 0xc7, 0x70, 0xa5, 0x8b, 0xf2, 0x28, 0x60, 0xd8, 0x1b, 0x7e, 0xd7, 0x1f, 0xc2, 0x92,
0x9e, 0x70, 0x68, 0xff, 0xb6, 0x3c, 0xaf, 0xb3, 0xb5, 0x23, 0xdf, 0xd2, 0xcf, 0x60, 0x49, 0x4f,
0xa8, 0xfc, 0x7b, 0x0f, 0x4a, 0xa1, 0x70, 0xbb, 0xee, 0xfa, 0x27, 0x81, 0xa2, 0x5d, 0x48, 0xd1,
0xca, 0xa0, 0xf6, 0xfc, 0x93, 0xc0, 0x86, 0x30, 0xf9, 0xb6, 0x5a, 0xf0, 0xbf, 0x0c, 0xef, 0x01,
0x89, 0xdc, 0xc0, 0x19, 0xd5, 0x5d, 0x74, 0x09, 0xf2, 0xa1, 0x60, 0x52, 0x49, 0xa9, 0x46, 0xd6,
0xe7, 0x60, 0x0d, 0x32, 0x37, 0x62, 0x30, 0xdf, 0xc2, 0xe5, 0x84, 0x7a, 0xe4, 0x10, 0x86, 0x48,
0x74, 0x1b, 0x8c, 0x5e, 0xfb, 0x23, 0xc6, 0xf4, 0x43, 0x0e, 0x96, 0x13, 0xd2, 0x7f, 0x68, 0x77,
0xfe, 0x7e, 0x68, 0xa9, 0x0d, 0x1d, 0xcf, 0x6c, 0xe8, 0xa7, 0x70, 0xb5, 0x9f, 0x77, 0x23, 0x06,
0xbe, 0x05, 0xd3, 0xfc, 0x38, 0x11, 0x67, 0xf8, 0x43, 0xb3, 0x06, 0x33, 0x31, 0x85, 0x72, 0x66,
0x1e, 0x26, 0x19, 0x3f, 0xd7, 0xea, 0xe4, 0xca, 0x81, 0xf5, 0x10, 0x16, 0x25, 0xee, 0x80, 0x44,
0xa3, 0x5f, 0x91, 0x56, 0x03, 0x4c, 0x1d, 0x9d, 0x72, 0x61, 0x07, 0x66, 0x89, 0xd0, 0x76, 0x1e,
0x10, 0xf5, 0x7e, 0x98, 0x29, 0x66, 0x49, 0xd0, 0x99, 0x5d, 0x21, 0x59, 0x81, 0xf5, 0x1c, 0x2a,
0x5d, 0x18, 0x7d, 0x70, 0xc3, 0xe4, 0xf1, 0x2e, 0xcc, 0x3f, 0xf5, 0x1d, 0x97, 0xb2, 0xc8, 0x3d,
0x6e, 0xb3, 0x51, 0x76, 0xe0, 0x36, 0x2c, 0x74, 0x31, 0x0d, 0xdc, 0x88, 0xf4, 0x01, 0x3e, 0xc0,
0xe7, 0x94, 0xb5, 0x8f, 0xdf, 0xe8, 0x01, 0xde, 0x4d, 0x1d, 0xe0, 0xc4, 0xbe, 0xf2, 0xf8, 0x16,
0x14, 0x42, 0x29, 0x52, 0x1e, 0xa0, 0x6c, 0x0e, 0x0b, 0x70, 0x0c, 0xe1, 0x05, 0xf2, 0xa8, 0x01,
0x58, 0x1f, 0x41, 0x65, 0x34, 0x27, 0xbe, 0x80, 0x79, 0x79, 0x26, 0x47, 0x5e, 0xcb, 0x7e, 0xf7,
0xf9, 0x0e, 0x2c, 0x74, 0x59, 0x18, 0xca, 0x51, 0xcd, 0x25, 0xf7, 0x2f, 0x6c, 0x7f, 0xdf, 0x4b,
0xee, 0x51, 0xcf, 0x25, 0x37, 0x5a, 0xb8, 0xef, 0x02, 0x74, 0x2e, 0x3d, 0xde, 0x5f, 0x9d, 0x12,
0x2f, 0xe9, 0xaf, 0xf8, 0x37, 0x97, 0x85, 0x58, 0x39, 0x3d, 0x6e, 0x8b, 0x6f, 0xeb, 0x8f, 0x31,
0x28, 0x28, 0x2a, 0x64, 0xc1, 0x74, 0x9b, 0xe2, 0x26, 0xa9, 0x63, 0x56, 0x8f, 0x08, 0x65, 0xa2,
0x89, 0xcc, 0xd9, 0x25, 0x21, 0xdc, 0xe2, 0x7d, 0x0d, 0x43, 0x57, 0xa0, 0x28, 0x31, 0x4d, 0xc2,
0xe2, 0x3e, 0x52, 0x08, 0x1e, 0x10, 0x86, 0xd6, 0x61, 0x36, 0x51, 0xd6, 0x23, 0x12, 0x62, 0x37,
0x32, 0xa6, 0x04, 0x66, 0x26, 0xc6, 0xd8, 0x42, 0x8a, 0xd6, 0xa0, 0xd2, 0x41, 0xca, 0x66, 0x00,
0x04, 0x70, 0x3a, 0x06, 0xca, 0x32, 0x7e, 0x05, 0xca, 0x8d, 0xa0, 0x15, 0x26, 0x1e, 0x95, 0x64,
0xa3, 0xcc, 0x65, 0xca, 0xa1, 0x45, 0x98, 0x12, 0x08, 0xee, 0x4f, 0x59, 0x68, 0x0b, 0x7c, 0xcc,
0xdd, 0x59, 0x83, 0x4a, 0xac, 0x8a, 0xbd, 0x99, 0x91, 0x46, 0x14, 0x42, 0x39, 0xb3, 0x0a, 0x33,
0x09, 0x4e, 0xfa, 0x32, 0x2b, 0x60, 0x65, 0x05, 0x93, 0xae, 0xc4, 0x2b, 0x8a, 0x34, 0x2b, 0xba,
0xd0, 0x59, 0x51, 0xb4, 0x02, 0xa5, 0xd4, 0xdd, 0x64, 0x5c, 0x12, 0xaa, 0xb4, 0x68, 0xf3, 0x09,
0x14, 0x0e, 0x59, 0x10, 0xe1, 0x26, 0x41, 0xf7, 0xa1, 0x98, 0xfc, 0x3a, 0x40, 0x57, 0x52, 0xdb,
0xdb, 0xfd, 0x5f, 0xc2, 0x5c, 0xd2, 0x2b, 0x65, 0xaa, 0x6c, 0xfa, 0x50, 0x4c, 0xfa, 0x6d, 0x84,
0xa1, 0x9c, 0xee, 0xb9, 0xd1, 0xf5, 0xd4, 0xd4, 0x41, 0x7d, 0xbe, 0xb9, 0xfe, 0x7a, 0xa0, 0xb2,
0xf7, 0xd3, 0x18, 0x4c, 0xf0, 0x64, 0x47, 0x77, 0xa1, 0xa0, 0xfa, 0x6d, 0xb4, 0x98, 0x9a, 0x9d,
0xed, 0xe3, 0x4d, 0x53, 0xa7, 0x52, 0x59, 0xbe, 0x0f, 0xa5, 0x54, 0xf3, 0x8c, 0x96, 0x53, 0xd0,
0xde, 0xe6, 0xdc, 0xbc, 0xda, 0x4f, 0xad, 0xd8, 0xf6, 0x00, 0x3a, 0x3d, 0x24, 0x5a, 0xea, 0xd3,
0x5a, 0x4a, 0xae, 0xe5, 0x81, 0x8d, 0x27, 0x7a, 0x01, 0x73, 0x3d, 0x0d, 0x17, 0xba, 0x36, 0xb8,
0x1d, 0x93, 0xc4, 0xab, 0x17, 0xe9, 0xd9, 0x36, 0x7f, 0x2f, 0x42, 0x5e, 0x9e, 0x58, 0xd4, 0x84,
0x79, 0x5d, 0x21, 0x8e, 0xd6, 0x52, 0x44, 0x03, 0x4a, 0x7f, 0xf3, 0xfa, 0x6b, 0x71, 0x2a, 0xa6,
0x73, 0x30, 0xfb, 0x97, 0xca, 0xe8, 0x56, 0x3f, 0x1a, 0x5d, 0x89, 0x68, 0xde, 0xbe, 0x20, 0x3a,
0x69, 0x72, 0x67, 0xbb, 0xeb, 0x58, 0x64, 0xa5, 0x28, 0xfa, 0x14, 0xd9, 0xe6, 0xb5, 0x81, 0x18,
0x45, 0xde, 0x82, 0x4b, 0xfa, 0x8a, 0x11, 0xad, 0xeb, 0xa6, 0x6b, 0xe3, 0xb9, 0x71, 0x01, 0xa4,
0x32, 0xf7, 0x21, 0xe4, 0x65, 0x9d, 0x84, 0x8c, 0x9e, 0xf2, 0x2a, 0xa6, 0x5b, 0xd4, 0x68, 0xd4,
0x74, 0x0c, 0xa8, 0xb7, 0x96, 0x43, 0xab, 0x3d, 0x13, 0x34, 0x95, 0xa3, 0xf9, 0xff, 0xd7, 0xa0,
0x94, 0x09, 0x0a, 0x46, 0xbf, 0xf6, 0x18, 0xbd, 0x95, 0xa6, 0x18, 0xdc, 0xcb, 0x9b, 0x37, 0x2f,
0x84, 0x55, 0x46, 0x9b, 0x30, 0xaf, 0xeb, 0x77, 0x33, 0x69, 0x3c, 0xa0, 0xc3, 0xce, 0xa4, 0xf1,
0xc0, 0xc6, 0xd9, 0x86, 0xe9, 0x4c, 0x05, 0x88, 0xaa, 0xa9, 0x99, 0xba, 0x2a, 0xd3, 0x5c, 0xe9,
0x0f, 0xd0, 0xe4, 0x67, 0xf2, 0x22, 0x6a, 0x53, 0x22, 0x53, 0x44, 0xe8, 0xf3, 0xb3, 0xfb, 0x29,
0xbf, 0xdb, 0x79, 0x65, 0x17, 0x35, 0x8f, 0xb8, 0xe6, 0x9a, 0xec, 0x66, 0xb0, 0x61, 0x3a, 0x53,
0x25, 0x64, 0x42, 0xd6, 0x55, 0x37, 0x99, 0x90, 0xf5, 0x05, 0x46, 0xef, 0xa9, 0x89, 0xc9, 0x07,
0x9c, 0x9a, 0x2e, 0x2b, 0x37, 0x2e, 0x80, 0x94, 0xe6, 0xb6, 0x57, 0x9f, 0x5b, 0x94, 0x05, 0xd1,
0x97, 0x35, 0x37, 0xd8, 0x10, 0x1f, 0x1b, 0x61, 0xe4, 0x9e, 0x61, 0x46, 0x36, 0x12, 0x8a, 0xf0,
0xf8, 0x38, 0x2f, 0xfe, 0x8b, 0xde, 0xf9, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x0b, 0xa9, 0x50, 0xaf,
0x10, 0x18, 0x00, 0x00,
// 1631 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4f, 0x53, 0xdc, 0xc6,
0x12, 0x7f, 0xe2, 0xcf, 0x2e, 0xf4, 0x2e, 0x2c, 0xcc, 0x03, 0x5b, 0xc8, 0x60, 0x78, 0x82, 0x87,
0xf1, 0xb3, 0xbd, 0xbc, 0xe0, 0x94, 0xab, 0x52, 0xe5, 0x54, 0x0c, 0x31, 0x36, 0x54, 0xb0, 0x8d,
0x05, 0x76, 0xa5, 0x9c, 0x94, 0x37, 0xc3, 0x6a, 0x58, 0x14, 0x6b, 0x25, 0x45, 0x9a, 0x25, 0xe1,
0x92, 0x63, 0xce, 0x39, 0xa7, 0xf2, 0x5d, 0x52, 0xb9, 0xa4, 0x7c, 0xca, 0x07, 0xc8, 0xc1, 0xf9,
0x0c, 0x39, 0xe5, 0x9a, 0x9a, 0x3f, 0xd2, 0x4a, 0xbb, 0xa3, 0x05, 0xef, 0xa6, 0x9c, 0x9b, 0xa6,
0xfb, 0x37, 0xbf, 0xee, 0x99, 0xe9, 0x19, 0x75, 0x37, 0x54, 0x9a, 0x2d, 0x97, 0x3a, 0x9e, 0x6f,
0x93, 0x6a, 0x10, 0xfa, 0xd4, 0x47, 0xe3, 0x89, 0xc0, 0x80, 0x86, 0xdf, 0xf0, 0x85, 0xd8, 0x58,
0x6c, 0xf8, 0x7e, 0xc3, 0x25, 0xeb, 0x7c, 0x74, 0xd4, 0x3a, 0x5e, 0xa7, 0x4e, 0x93, 0x44, 0x14,
0x37, 0x03, 0x01, 0x30, 0xd7, 0x60, 0xc2, 0x22, 0x5f, 0xb5, 0x48, 0x44, 0x77, 0x08, 0xb6, 0x49,
0x88, 0x2e, 0x43, 0x11, 0x07, 0x4e, 0xed, 0x15, 0x39, 0xd3, 0xb5, 0x25, 0x6d, 0xad, 0x6c, 0x15,
0x70, 0xe0, 0x7c, 0x42, 0xce, 0xcc, 0xfb, 0x30, 0x75, 0xdf, 0x89, 0x5e, 0x1d, 0x04, 0xb8, 0x4e,
0xe4, 0x14, 0xf4, 0x7f, 0x28, 0x9c, 0xf0, 0x69, 0x1c, 0x5b, 0xda, 0xd0, 0xab, 0x6d, 0xbf, 0x32,
0xb4, 0x96, 0xc4, 0x99, 0x3f, 0x69, 0x30, 0x9d, 0xa2, 0x89, 0x02, 0xdf, 0x8b, 0x08, 0x9a, 0x87,
0x71, 0xec, 0xba, 0x7e, 0x1d, 0x53, 0x62, 0x73, 0xaa, 0x61, 0xab, 0x2d, 0x40, 0x8b, 0x50, 0x6a,
0x45, 0xc4, 0xae, 0x05, 0x0e, 0xa9, 0x93, 0x48, 0x1f, 0xe2, 0x7a, 0x60, 0xa2, 0x7d, 0x2e, 0x41,
0x0b, 0xc0, 0x47, 0x35, 0x1a, 0xe2, 0xe8, 0x44, 0x1f, 0x16, 0xf3, 0x99, 0xe4, 0x90, 0x09, 0x10,
0x82, 0x91, 0xe3, 0x90, 0x10, 0x7d, 0x84, 0x2b, 0xf8, 0x37, 0xb7, 0x78, 0x8a, 0x1d, 0x17, 0x1f,
0xb9, 0x44, 0x1f, 0x95, 0x16, 0x63, 0x01, 0x32, 0x60, 0xcc, 0x3f, 0x25, 0x21, 0xa3, 0xd0, 0x0b,
0x5c, 0x99, 0x8c, 0xcd, 0x7d, 0x98, 0xdf, 0xc2, 0x9e, 0xfd, 0xb5, 0x63, 0xd3, 0x93, 0x47, 0xbe,
0x47, 0x4f, 0x0e, 0x5a, 0xcd, 0x26, 0x0e, 0xcf, 0xfa, 0xdf, 0x93, 0xdb, 0xb0, 0x90, 0xc3, 0x28,
0xb7, 0x07, 0xc1, 0x08, 0x77, 0x45, 0xec, 0x0c, 0xff, 0x36, 0xb7, 0x60, 0xf2, 0x39, 0x09, 0x23,
0xc7, 0xf7, 0xfa, 0x37, 0x7c, 0x03, 0x2a, 0x09, 0x87, 0x34, 0xa5, 0x43, 0xf1, 0x54, 0x88, 0x38,
0xcb, 0xb8, 0x15, 0x0f, 0xcd, 0x07, 0x80, 0xf6, 0x70, 0x44, 0x3f, 0xf6, 0x3d, 0x8a, 0xeb, 0xb4,
0x7f, 0xa3, 0x2f, 0xe1, 0xdf, 0x19, 0x1e, 0x69, 0xf8, 0x21, 0x94, 0x5d, 0x1c, 0xd1, 0x5a, 0x5d,
0xc8, 0x25, 0x9d, 0x51, 0x15, 0x01, 0x5c, 0x8d, 0x03, 0xb8, 0x7a, 0x18, 0x07, 0xf0, 0xd6, 0xd8,
0xeb, 0x37, 0x8b, 0xff, 0xfa, 0xfe, 0xf7, 0x45, 0xcd, 0x2a, 0xb9, 0x6d, 0x42, 0xf3, 0x1b, 0x98,
0xb6, 0x48, 0xd0, 0xa2, 0x98, 0x0e, 0xb2, 0x37, 0xe8, 0x3d, 0x28, 0x47, 0x98, 0x12, 0xd7, 0x75,
0x28, 0xa9, 0x39, 0x36, 0x8f, 0xba, 0xf2, 0xd6, 0x24, 0xb3, 0xf9, 0xdb, 0x9b, 0xc5, 0xc2, 0x63,
0xdf, 0x26, 0xbb, 0xf7, 0xad, 0x52, 0x82, 0xd9, 0xb5, 0xcd, 0x3f, 0x35, 0x40, 0x69, 0xd3, 0x72,
0x65, 0x77, 0xa1, 0xe0, 0x7b, 0xae, 0xe3, 0x11, 0x69, 0x7b, 0x25, 0x63, 0xbb, 0x13, 0x5e, 0x7d,
0xc2, 0xb1, 0x96, 0x9c, 0x83, 0x3e, 0x80, 0x51, 0xdc, 0xb2, 0x1d, 0xca, 0x1d, 0x28, 0x6d, 0x2c,
0xf7, 0x9e, 0xbc, 0xc9, 0xa0, 0x96, 0x98, 0x61, 0x5c, 0x85, 0x82, 0x20, 0x43, 0x33, 0x30, 0x1a,
0xd5, 0xfd, 0x50, 0x78, 0xa0, 0x59, 0x62, 0x60, 0xec, 0xc0, 0x28, 0xc7, 0xab, 0xd5, 0xe8, 0x3a,
0x4c, 0x45, 0xad, 0x28, 0x20, 0x1e, 0x3b, 0xfe, 0x9a, 0x00, 0x0c, 0x71, 0x40, 0xa5, 0x2d, 0x3f,
0x60, 0x62, 0x73, 0x0f, 0xf4, 0xc3, 0xb0, 0x15, 0x51, 0x62, 0x1f, 0xc4, 0xfb, 0x11, 0xf5, 0x1f,
0x21, 0xbf, 0x68, 0x30, 0xa7, 0xa0, 0x93, 0xdb, 0xf9, 0x19, 0x20, 0x2a, 0x94, 0xb5, 0x64, 0xf3,
0x23, 0x5d, 0x5b, 0x1a, 0x5e, 0x2b, 0x6d, 0xdc, 0x4c, 0x71, 0xe7, 0x32, 0x54, 0xd9, 0xd9, 0x3d,
0xb3, 0xf6, 0xac, 0x69, 0xda, 0x09, 0x31, 0xf6, 0xa0, 0x28, 0xb5, 0xe8, 0x1a, 0x14, 0x19, 0x0f,
0x3b, 0x7b, 0x4d, 0x79, 0xf6, 0x05, 0xa6, 0xde, 0xb5, 0xd9, 0x95, 0xc1, 0xb6, 0x1d, 0x92, 0x48,
0x3c, 0x4d, 0xe3, 0x56, 0x3c, 0x34, 0xbf, 0xd3, 0x60, 0x71, 0x3b, 0xa2, 0x4e, 0x93, 0x3d, 0x63,
0xfb, 0xf8, 0xcc, 0x6f, 0xd1, 0xc4, 0xd6, 0x3b, 0x8d, 0xcc, 0xa7, 0xb0, 0x94, 0xef, 0x87, 0xdc,
0xd7, 0x5b, 0x80, 0x48, 0x8c, 0xa9, 0x11, 0x1c, 0x7a, 0x8e, 0xd7, 0x88, 0xe4, 0x93, 0x33, 0x9d,
0x68, 0xb6, 0xa5, 0xc2, 0x7c, 0x02, 0x57, 0x3a, 0x28, 0x0f, 0x7d, 0x8a, 0xdd, 0xfe, 0x4f, 0xfd,
0x11, 0xcc, 0xab, 0x09, 0xfb, 0xf6, 0x6f, 0xd3, 0x75, 0xdb, 0x47, 0x3b, 0xf0, 0x2b, 0xfd, 0x1c,
0xe6, 0xd5, 0x84, 0xd2, 0xbf, 0x3b, 0x50, 0x0a, 0xb8, 0xdb, 0x35, 0xc7, 0x3b, 0xf6, 0x25, 0xed,
0x6c, 0x8a, 0x56, 0x2c, 0x6a, 0xd7, 0x3b, 0xf6, 0x2d, 0x08, 0x92, 0x6f, 0xb3, 0x09, 0xff, 0xc9,
0xf0, 0xee, 0x93, 0xd0, 0xf1, 0xed, 0x41, 0xdd, 0x45, 0x97, 0xa0, 0x10, 0x70, 0x26, 0x19, 0x94,
0x72, 0x64, 0x7e, 0x0e, 0x66, 0x2f, 0x73, 0x03, 0x2e, 0xe6, 0x5b, 0xb8, 0x9c, 0x50, 0x0f, 0xbc,
0x84, 0x3e, 0x02, 0xdd, 0x02, 0xbd, 0xdb, 0xfe, 0x80, 0x6b, 0xfa, 0x51, 0x83, 0x85, 0x84, 0xf4,
0x6f, 0x3a, 0x9d, 0xb7, 0x5f, 0x5a, 0xea, 0x40, 0x87, 0x33, 0x07, 0xfa, 0x29, 0x5c, 0xcd, 0xf3,
0x6e, 0xc0, 0x85, 0x6f, 0xc2, 0x04, 0xbb, 0x4e, 0xc4, 0xee, 0xff, 0xd2, 0xac, 0xc2, 0x64, 0x4c,
0x21, 0x9d, 0x99, 0x81, 0x51, 0xca, 0xee, 0xb5, 0xbc, 0xb9, 0x62, 0x60, 0x3e, 0x82, 0x39, 0x81,
0xdb, 0x27, 0xe1, 0xe0, 0x4f, 0xa4, 0x59, 0x07, 0x43, 0x45, 0x27, 0x5d, 0xd8, 0x86, 0x29, 0xc2,
0xb5, 0xed, 0x1f, 0x88, 0xfc, 0x7f, 0x18, 0x29, 0x66, 0x41, 0xd0, 0x9e, 0x5d, 0x21, 0x59, 0x81,
0xf9, 0x02, 0x2a, 0x1d, 0x18, 0xf5, 0xe2, 0xfa, 0x89, 0xe3, 0x1d, 0x98, 0x79, 0xe6, 0xd9, 0x4e,
0x44, 0x43, 0xe7, 0xa8, 0x45, 0x07, 0x39, 0x81, 0x5b, 0x30, 0xdb, 0xc1, 0xd4, 0xf3, 0x20, 0xd2,
0x17, 0x78, 0x1f, 0x9f, 0x45, 0xb4, 0x75, 0xf4, 0x4e, 0x2f, 0xf0, 0x4e, 0xea, 0x02, 0x27, 0xf6,
0xa5, 0xc7, 0x37, 0xa1, 0x18, 0x08, 0x91, 0xf4, 0x00, 0x65, 0x63, 0x98, 0x83, 0x63, 0x08, 0x4b,
0x90, 0x07, 0x5d, 0x80, 0xf9, 0x11, 0x54, 0x06, 0x73, 0xe2, 0x0b, 0x98, 0x11, 0x77, 0x72, 0xe0,
0xbd, 0xcc, 0x7b, 0xcf, 0xb7, 0x61, 0xb6, 0xc3, 0x42, 0x5f, 0x8e, 0x2a, 0x1e, 0xb9, 0x7f, 0xe0,
0xf8, 0x73, 0x1f, 0xb9, 0xc7, 0x5d, 0x8f, 0xdc, 0x60, 0xcb, 0x7d, 0x1f, 0xa0, 0xfd, 0xe8, 0xb1,
0xfa, 0xea, 0x84, 0xb8, 0x49, 0x7d, 0xc5, 0xbe, 0x99, 0x2c, 0xc0, 0xd2, 0xe9, 0x61, 0x8b, 0x7f,
0x9b, 0x7f, 0x0c, 0x41, 0x51, 0x52, 0x21, 0x13, 0x26, 0x5a, 0x11, 0x6e, 0x90, 0x1a, 0xa6, 0xb5,
0x90, 0x44, 0x94, 0x17, 0x91, 0x9a, 0x55, 0xe2, 0xc2, 0x4d, 0x56, 0xd7, 0x50, 0x74, 0x05, 0xc6,
0x05, 0xa6, 0x41, 0x68, 0x5c, 0x47, 0x72, 0xc1, 0x43, 0x42, 0xd1, 0x1a, 0x4c, 0x25, 0xca, 0x5a,
0x48, 0x02, 0xec, 0x84, 0xfa, 0x18, 0xc7, 0x4c, 0xc6, 0x18, 0x8b, 0x4b, 0xd1, 0x2a, 0x54, 0xda,
0x48, 0x51, 0x0c, 0x00, 0x07, 0x4e, 0xc4, 0x40, 0x91, 0xc6, 0x2f, 0x41, 0xb9, 0xee, 0x37, 0x83,
0xc4, 0xa3, 0x92, 0x28, 0x94, 0x99, 0x4c, 0x3a, 0x34, 0x07, 0x63, 0x1c, 0xc1, 0xfc, 0x29, 0x73,
0x6d, 0x91, 0x8d, 0x99, 0x3b, 0xab, 0x50, 0x89, 0x55, 0xb1, 0x37, 0x93, 0xc2, 0x88, 0x44, 0x48,
0x67, 0x56, 0x60, 0x32, 0xc1, 0x09, 0x5f, 0xa6, 0x38, 0xac, 0x2c, 0x61, 0xc2, 0x95, 0x78, 0x47,
0x91, 0x62, 0x47, 0x67, 0xdb, 0x3b, 0x8a, 0x96, 0xa0, 0x94, 0x7a, 0x9b, 0xf4, 0x4b, 0x5c, 0x95,
0x16, 0xb1, 0xd2, 0x62, 0x87, 0xb8, 0xf6, 0x66, 0xd3, 0x6f, 0x79, 0x74, 0xc7, 0x89, 0xa8, 0x3f,
0x48, 0x12, 0xf7, 0x7a, 0x08, 0xe6, 0x14, 0x74, 0x32, 0x86, 0xf6, 0xa1, 0x78, 0x22, 0x44, 0xf2,
0x7f, 0x70, 0x27, 0x45, 0x98, 0x3b, 0x4d, 0xa1, 0x89, 0x69, 0x8c, 0xbb, 0x00, 0x6d, 0x6d, 0x2a,
0xba, 0xb5, 0x74, 0x74, 0x33, 0x39, 0xe6, 0x08, 0x19, 0x6d, 0x72, 0x64, 0xfc, 0xa0, 0xc1, 0x74,
0x17, 0x79, 0xd7, 0xb5, 0xd2, 0xce, 0xbf, 0x56, 0x16, 0x94, 0xd9, 0x11, 0xd4, 0x04, 0x2f, 0xab,
0x53, 0xd8, 0xea, 0xd6, 0xdf, 0x72, 0x75, 0x56, 0xe9, 0x24, 0xf9, 0x8e, 0x36, 0x9e, 0x42, 0xf1,
0x80, 0xfa, 0x21, 0x6e, 0x10, 0xf4, 0x00, 0xc6, 0x93, 0x9e, 0x0e, 0xba, 0x92, 0x62, 0xed, 0x6c,
0x18, 0x19, 0xf3, 0x6a, 0xa5, 0x30, 0xb5, 0xe1, 0xc1, 0x78, 0xd2, 0x08, 0x41, 0x18, 0xca, 0xe9,
0x66, 0x08, 0xba, 0x96, 0x9a, 0xda, 0xab, 0x01, 0x63, 0xac, 0x9d, 0x0f, 0x94, 0xf6, 0x7e, 0x1e,
0x82, 0x11, 0xb6, 0x5d, 0xe8, 0x1e, 0x14, 0x65, 0x23, 0x04, 0xcd, 0xa5, 0x66, 0x67, 0x1b, 0x2c,
0x86, 0xa1, 0x52, 0xc9, 0xd0, 0xd9, 0x83, 0x52, 0xaa, 0xab, 0x81, 0x16, 0x52, 0xd0, 0xee, 0xae,
0x89, 0x71, 0x35, 0x4f, 0x2d, 0xd9, 0x76, 0x01, 0xda, 0xc5, 0x3d, 0x9a, 0xcf, 0xa9, 0xf9, 0x05,
0xd7, 0x42, 0xcf, 0x8e, 0x00, 0x7a, 0x09, 0xd3, 0x5d, 0x95, 0x30, 0x5a, 0xee, 0x5d, 0x27, 0x0b,
0xe2, 0x95, 0x8b, 0x14, 0xd3, 0x1b, 0xbf, 0x02, 0x14, 0xc4, 0x53, 0x8a, 0x1a, 0x30, 0xa3, 0xaa,
0x90, 0xd0, 0x6a, 0x8a, 0xa8, 0x47, 0x4d, 0x66, 0x5c, 0x3b, 0x17, 0x27, 0xd7, 0x74, 0x06, 0x46,
0x7e, 0x0d, 0x83, 0x6e, 0xe6, 0xd1, 0xa8, 0x72, 0x77, 0xe3, 0xd6, 0x05, 0xd1, 0x49, 0xf7, 0x61,
0xaa, 0xb3, 0xc0, 0x40, 0x66, 0x8a, 0x22, 0xa7, 0xfa, 0x31, 0x96, 0x7b, 0x62, 0x24, 0x79, 0x13,
0x2e, 0xa9, 0x53, 0x79, 0xb4, 0xa6, 0x9a, 0xae, 0x5c, 0xcf, 0xf5, 0x0b, 0x20, 0xa5, 0xb9, 0x0f,
0xa1, 0x20, 0x12, 0x58, 0xa4, 0x77, 0xe5, 0xbd, 0x31, 0xdd, 0x9c, 0x42, 0x23, 0xa7, 0x63, 0x40,
0xdd, 0x49, 0x36, 0x5a, 0xe9, 0x9a, 0xa0, 0x48, 0xe9, 0x8d, 0xff, 0x9e, 0x83, 0x92, 0x26, 0x22,
0xd0, 0xf3, 0xfa, 0x16, 0xe8, 0x7f, 0x69, 0x8a, 0xde, 0x4d, 0x16, 0xe3, 0xc6, 0x85, 0xb0, 0xd2,
0x68, 0x03, 0x66, 0x54, 0x8d, 0x88, 0x4c, 0x18, 0xf7, 0x68, 0x7d, 0x64, 0xc2, 0xb8, 0x67, 0x47,
0xc3, 0x82, 0x89, 0x4c, 0x6a, 0x8e, 0x16, 0x53, 0x33, 0x55, 0xe9, 0xbf, 0xb1, 0x94, 0x0f, 0x50,
0xc4, 0x67, 0x92, 0xaa, 0x28, 0x43, 0x22, 0x93, 0xdd, 0xa9, 0xe3, 0xb3, 0x33, 0xc7, 0xba, 0xd7,
0x4e, 0x7f, 0xe6, 0x14, 0xd9, 0x95, 0xe2, 0x99, 0xec, 0x64, 0xb0, 0x60, 0x22, 0x93, 0xbe, 0x65,
0x96, 0xac, 0x4a, 0x3b, 0x33, 0x4b, 0x56, 0x67, 0x7e, 0xdd, 0xb7, 0x26, 0x26, 0xef, 0x71, 0x6b,
0x3a, 0xac, 0x5c, 0xbf, 0x00, 0xb2, 0xfd, 0xa0, 0x76, 0xff, 0x93, 0x97, 0x7b, 0xff, 0x4a, 0xbb,
0x1f, 0xd4, 0xdc, 0xff, 0xed, 0xd6, 0xca, 0x0b, 0x93, 0x09, 0xbe, 0xac, 0x3a, 0xfe, 0x3a, 0xff,
0x58, 0x0f, 0x42, 0xe7, 0x14, 0x53, 0xb2, 0x9e, 0xcc, 0x0e, 0x8e, 0x8e, 0x0a, 0xbc, 0x21, 0x7e,
0xfb, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xad, 0x32, 0x36, 0xd4, 0x09, 0x1a, 0x00, 0x00,
}

View File

@ -110,6 +110,7 @@ service Payout {
rpc Paystub(PaystubRequest) returns (PaystubResponse);
rpc PeriodPaystub(PeriodPaystubRequest) returns (PeriodPaystubResponse);
rpc SatellitePeriodPaystub(SatellitePeriodPaystubRequest) returns (SatellitePeriodPaystubResponse);
rpc HeldAmountHistory(HeldAmountHistoryRequest) returns (HeldAmountHistoryResponse);
}
message EstimatedPayoutSatelliteRequest {
@ -245,3 +246,21 @@ message Paystub {
int64 paid = 21;
int64 distributed = 22;
}
message HeldAmountHistoryRequest {
RequestHeader header = 1;
}
message HeldAmountHistoryResponse {
message HeldAmount {
string period = 1;
int64 amount = 2;
}
message HeldAmountHistory {
bytes satellite_id = 1 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false];
repeated HeldAmount held_amounts = 2;
}
repeated HeldAmountHistory history = 1;
}

View File

@ -400,6 +400,7 @@ type DRPCPayoutClient interface {
Paystub(ctx context.Context, in *PaystubRequest) (*PaystubResponse, error)
PeriodPaystub(ctx context.Context, in *PeriodPaystubRequest) (*PeriodPaystubResponse, error)
SatellitePeriodPaystub(ctx context.Context, in *SatellitePeriodPaystubRequest) (*SatellitePeriodPaystubResponse, error)
HeldAmountHistory(ctx context.Context, in *HeldAmountHistoryRequest) (*HeldAmountHistoryResponse, error)
}
type drpcPayoutClient struct {
@ -529,6 +530,15 @@ func (c *drpcPayoutClient) SatellitePeriodPaystub(ctx context.Context, in *Satel
return out, nil
}
func (c *drpcPayoutClient) HeldAmountHistory(ctx context.Context, in *HeldAmountHistoryRequest) (*HeldAmountHistoryResponse, error) {
out := new(HeldAmountHistoryResponse)
err := c.cc.Invoke(ctx, "/multinode.Payout/HeldAmountHistory", drpcEncoding_File_multinode_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
type DRPCPayoutServer interface {
AllSatellitesSummary(context.Context, *AllSatellitesSummaryRequest) (*AllSatellitesSummaryResponse, error)
AllSatellitesPeriodSummary(context.Context, *AllSatellitesPeriodSummaryRequest) (*AllSatellitesPeriodSummaryResponse, error)
@ -543,6 +553,7 @@ type DRPCPayoutServer interface {
Paystub(context.Context, *PaystubRequest) (*PaystubResponse, error)
PeriodPaystub(context.Context, *PeriodPaystubRequest) (*PeriodPaystubResponse, error)
SatellitePeriodPaystub(context.Context, *SatellitePeriodPaystubRequest) (*SatellitePeriodPaystubResponse, error)
HeldAmountHistory(context.Context, *HeldAmountHistoryRequest) (*HeldAmountHistoryResponse, error)
}
type DRPCPayoutUnimplementedServer struct{}
@ -599,9 +610,13 @@ func (s *DRPCPayoutUnimplementedServer) SatellitePeriodPaystub(context.Context,
return nil, drpcerr.WithCode(errors.New("Unimplemented"), 12)
}
func (s *DRPCPayoutUnimplementedServer) HeldAmountHistory(context.Context, *HeldAmountHistoryRequest) (*HeldAmountHistoryResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), 12)
}
type DRPCPayoutDescription struct{}
func (DRPCPayoutDescription) NumMethods() int { return 13 }
func (DRPCPayoutDescription) NumMethods() int { return 14 }
func (DRPCPayoutDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
switch n {
@ -722,6 +737,15 @@ func (DRPCPayoutDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver
in1.(*SatellitePeriodPaystubRequest),
)
}, DRPCPayoutServer.SatellitePeriodPaystub, true
case 13:
return "/multinode.Payout/HeldAmountHistory", drpcEncoding_File_multinode_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCPayoutServer).
HeldAmountHistory(
ctx,
in1.(*HeldAmountHistoryRequest),
)
}, DRPCPayoutServer.HeldAmountHistory, true
default:
return "", nil, nil, nil, false
}
@ -938,3 +962,19 @@ func (x *drpcPayout_SatellitePeriodPaystubStream) SendAndClose(m *SatellitePerio
}
return x.CloseSend()
}
type DRPCPayout_HeldAmountHistoryStream interface {
drpc.Stream
SendAndClose(*HeldAmountHistoryResponse) error
}
type drpcPayout_HeldAmountHistoryStream struct {
drpc.Stream
}
func (x *drpcPayout_HeldAmountHistoryStream) SendAndClose(m *HeldAmountHistoryResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_multinode_proto{}); err != nil {
return err
}
return x.CloseSend()
}

View File

@ -26,17 +26,19 @@ type PayoutEndpoint struct {
log *zap.Logger
apiKeys *apikeys.Service
estimatedPayouts *estimatedpayouts.Service
db payouts.DB
service *payouts.Service
estimatedPayouts *estimatedpayouts.Service
}
// NewPayoutEndpoint creates new multinode payouts endpoint.
func NewPayoutEndpoint(log *zap.Logger, apiKeys *apikeys.Service, estimatedPayouts *estimatedpayouts.Service, db payouts.DB) *PayoutEndpoint {
func NewPayoutEndpoint(log *zap.Logger, apiKeys *apikeys.Service, db payouts.DB, estimatedPayouts *estimatedpayouts.Service, service *payouts.Service) *PayoutEndpoint {
return &PayoutEndpoint{
log: log,
apiKeys: apiKeys,
estimatedPayouts: estimatedPayouts,
db: db,
service: service,
estimatedPayouts: estimatedPayouts,
}
}
@ -336,3 +338,37 @@ func (payout *PayoutEndpoint) SatellitePeriodPaystub(ctx context.Context, req *m
Distributed: paystub.Distributed,
}}, nil
}
// HeldAmountHistory returns held amount history for all satellites.
func (payout *PayoutEndpoint) HeldAmountHistory(ctx context.Context, req *multinodepb.HeldAmountHistoryRequest) (_ *multinodepb.HeldAmountHistoryResponse, err error) {
defer mon.Task()(&ctx)(&err)
if err = authenticate(ctx, payout.apiKeys, req.GetHeader()); err != nil {
return nil, rpcstatus.Wrap(rpcstatus.Unauthenticated, err)
}
heldHistory, err := payout.service.HeldAmountHistory(ctx)
if err != nil {
return nil, rpcstatus.Wrap(rpcstatus.Internal, err)
}
resp := new(multinodepb.HeldAmountHistoryResponse)
for _, satelliteHeldHistory := range heldHistory {
var pbHeldAmount []*multinodepb.HeldAmountHistoryResponse_HeldAmount
for _, heldAmount := range satelliteHeldHistory.HeldAmounts {
pbHeldAmount = append(pbHeldAmount, &multinodepb.HeldAmountHistoryResponse_HeldAmount{
Period: heldAmount.Period,
Amount: heldAmount.Amount,
})
}
resp.History = append(resp.History, &multinodepb.HeldAmountHistoryResponse_HeldAmountHistory{
SatelliteId: satelliteHeldHistory.SatelliteID,
HeldAmounts: pbHeldAmount,
})
}
return resp, nil
}

View File

@ -66,8 +66,10 @@ func TestPayoutsEndpointSummary(t *testing.T) {
require.NoError(t, err)
require.NoError(t, trustPool.Refresh(ctx))
payoutsService, err := payouts.NewService(log, db.Payout(), db.Reputation(), db.Satellites(), trustPool)
require.NoError(t, err)
estimatedPayoutsService := estimatedpayouts.NewService(db.Bandwidth(), db.Reputation(), db.StorageUsage(), db.Pricing(), db.Satellites(), trustPool)
endpoint := multinode.NewPayoutEndpoint(log, service, estimatedPayoutsService, db.Payout())
endpoint := multinode.NewPayoutEndpoint(log, service, db.Payout(), estimatedPayoutsService, payoutsService)
id := testrand.NodeID()
id2 := testrand.NodeID()
@ -157,8 +159,10 @@ func TestPayoutsEndpointEstimations(t *testing.T) {
require.NoError(t, err)
require.NoError(t, trustPool.Refresh(ctx))
payoutsService, err := payouts.NewService(log, db.Payout(), db.Reputation(), db.Satellites(), trustPool)
require.NoError(t, err)
estimatedPayoutsService := estimatedpayouts.NewService(db.Bandwidth(), db.Reputation(), db.StorageUsage(), db.Pricing(), db.Satellites(), trustPool)
endpoint := multinode.NewPayoutEndpoint(log, service, estimatedPayoutsService, db.Payout())
endpoint := multinode.NewPayoutEndpoint(log, service, db.Payout(), estimatedPayoutsService, payoutsService)
now := time.Now().UTC().Add(-2 * time.Hour)
@ -226,8 +230,11 @@ func TestPayoutsUndistributedEndpoint(t *testing.T) {
require.NoError(t, err)
require.NoError(t, trustPool.Refresh(ctx))
payoutsService, err := payouts.NewService(log, db.Payout(), db.Reputation(), db.Satellites(), trustPool)
require.NoError(t, err)
estimatedPayoutsService := estimatedpayouts.NewService(db.Bandwidth(), db.Reputation(), db.StorageUsage(), db.Pricing(), db.Satellites(), trustPool)
endpoint := multinode.NewPayoutEndpoint(log, service, estimatedPayoutsService, db.Payout())
endpoint := multinode.NewPayoutEndpoint(log, service, db.Payout(), estimatedPayoutsService, payoutsService)
satelliteID1 := testrand.NodeID()
satelliteID2 := testrand.NodeID()

View File

@ -575,3 +575,108 @@ func TestSummedPaystubs(t *testing.T) {
})
})
}
func TestDBHeldAmountHistory(t *testing.T) {
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {
payoutsDB := db.Payout()
satelliteID1 := testrand.NodeID()
satelliteID2 := testrand.NodeID()
paystubs := []payouts.PayStub{
{
SatelliteID: satelliteID1,
Period: "2021-01",
Held: 10,
},
{
SatelliteID: satelliteID1,
Period: "2021-02",
Held: 10,
},
{
SatelliteID: satelliteID1,
Period: "2021-03",
Held: 10,
},
{
SatelliteID: satelliteID1,
Period: "2021-04",
Held: 10,
},
{
SatelliteID: satelliteID2,
Period: "2021-01",
Held: 0,
},
{
SatelliteID: satelliteID2,
Period: "2021-02",
Held: 0,
},
{
SatelliteID: satelliteID2,
Period: "2021-03",
Held: 0,
},
{
SatelliteID: satelliteID2,
Period: "2021-04",
Held: 0,
},
}
expected := []payouts.HeldAmountHistory{
{
SatelliteID: satelliteID1,
HeldAmounts: []payouts.HeldForPeriod{
{
Period: "2021-01",
Amount: 10,
},
{
Period: "2021-02",
Amount: 10,
},
{
Period: "2021-03",
Amount: 10,
},
{
Period: "2021-04",
Amount: 10,
},
},
},
{
SatelliteID: satelliteID2,
HeldAmounts: []payouts.HeldForPeriod{
{
Period: "2021-01",
Amount: 0,
},
{
Period: "2021-02",
Amount: 0,
},
{
Period: "2021-03",
Amount: 0,
},
{
Period: "2021-04",
Amount: 0,
},
},
},
}
for _, paystub := range paystubs {
err := payoutsDB.StorePayStub(ctx, paystub)
require.NoError(t, err)
}
history, err := payoutsDB.HeldAmountHistory(ctx)
require.NoError(t, err)
require.ElementsMatch(t, expected, history)
})
}

View File

@ -23,7 +23,7 @@ type DB interface {
// AllPayStubs retrieves paystubs from all satellites in specific period from DB.
AllPayStubs(ctx context.Context, period string) ([]PayStub, error)
// SatellitesHeldbackHistory retrieves heldback history for specific satellite from DB.
SatellitesHeldbackHistory(ctx context.Context, satelliteID storj.NodeID) ([]HoldForPeriod, error)
SatellitesHeldbackHistory(ctx context.Context, satelliteID storj.NodeID) ([]HeldForPeriod, error)
// SatellitesDisposedHistory returns all disposed amount for specific satellite from DB.
SatellitesDisposedHistory(ctx context.Context, satelliteID storj.NodeID) (int64, error)
// SatellitePeriods retrieves all periods for concrete satellite in which we have some payouts data.
@ -54,6 +54,8 @@ type DB interface {
GetPeriodPaystubs(ctx context.Context, period string) (*PayStub, error)
// GetSatellitePeriodPaystubs returns summed satellite paystubs for specific period.
GetSatellitePeriodPaystubs(ctx context.Context, period string, satelliteID storj.NodeID) (*PayStub, error)
// HeldAmountHistory retrieves held amount history for all satellites.
HeldAmountHistory(ctx context.Context) ([]HeldAmountHistory, error)
}
// ErrNoPayStubForPeriod represents errors from the payouts database.
@ -85,10 +87,17 @@ type PayStub struct {
Distributed int64 `json:"distributed"`
}
// HoldForPeriod is node's held amount for period.
type HoldForPeriod struct {
Period string `json:"period"`
Amount int64 `json:"amount"`
// GetEarnedWithSurge returns paystub's total earned and surge.
func (paystub *PayStub) GetEarnedWithSurge() (earned int64, surge int64) {
earned = paystub.CompGetAudit + paystub.CompGet + paystub.CompGetRepair + paystub.CompAtRest
surge = earned * paystub.SurgePercent / 100
return earned, surge
}
// UsageAtRestTbM converts paystub's usage_at_rest from tbh to tbm.
func (paystub *PayStub) UsageAtRestTbM() {
paystub.UsageAtRest /= 720
}
// Payment is node payment data for specific period.
@ -132,6 +141,18 @@ type SatellitePayoutForPeriod struct {
Distributed int64 `json:"distributed"`
}
// HeldAmountHistory contains held amount history for satellite.
type HeldAmountHistory struct {
SatelliteID storj.NodeID `json:"satelliteId"`
HeldAmounts []HeldForPeriod `json:"heldAmounts"`
}
// HeldForPeriod is node's held amount for period.
type HeldForPeriod struct {
Period string `json:"period"`
Amount int64 `json:"amount"`
}
// Period is a string that represents paystub period type in format yyyy-mm.
type Period string
@ -139,16 +160,3 @@ type Period string
func (p Period) Time() (time.Time, error) {
return time.Parse("2006-01", string(p))
}
// GetEarnedWithSurge returns paystub's total earned and surge.
func (paystub *PayStub) GetEarnedWithSurge() (earned int64, surge int64) {
earned = paystub.CompGetAudit + paystub.CompGet + paystub.CompGetRepair + paystub.CompAtRest
surge = earned * paystub.SurgePercent / 100
return earned, surge
}
// UsageAtRestTbM converts paystub's usage_at_rest from tbh to tbm.
func (paystub *PayStub) UsageAtRestTbM() {
paystub.UsageAtRest /= 720
}

View File

@ -0,0 +1,42 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package payouts
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestParsePeriodRange(t *testing.T) {
testCases := [...]struct {
periodStart string
periodEnd string
periods []string
}{
{"2020-01", "2020-02", []string{"2020-01", "2020-02"}},
{"2020-01", "2020-01", []string{"2020-01"}},
{"2019-11", "2020-02", []string{"2019-11", "2019-12", "2020-01", "2020-02"}},
{"", "2020-02", nil},
{"2020-01", "", nil},
{"2020-01-01", "2020-02", nil},
{"2020-44", "2020-02", nil},
{"2020-01", "2020-44", nil},
{"2020-01", "2019-01", nil},
{"2020-02", "2020-01", nil},
}
for _, tc := range testCases {
periods, err := parsePeriodRange(tc.periodStart, tc.periodEnd)
require.Equal(t, len(periods), len(tc.periods))
if periods != nil {
for i := 0; i < len(periods); i++ {
require.Equal(t, periods[i], tc.periods[i])
require.NoError(t, err)
}
} else {
require.Error(t, err)
}
}
}

View File

@ -316,6 +316,37 @@ func (service *Service) AllSatellitesPayoutPeriod(ctx context.Context, period st
return result, nil
}
// HeldAmountHistory retrieves held amount history for all satellites.
func (service *Service) HeldAmountHistory(ctx context.Context) (_ []HeldAmountHistory, err error) {
defer mon.Task()(&ctx)(&err)
heldHistory, err := service.db.HeldAmountHistory(ctx)
if err != nil {
return nil, ErrPayoutService.Wrap(err)
}
trustedSatellites := service.trust.GetSatellites(ctx)
for _, trustedSatellite := range trustedSatellites {
var found bool
for _, satelliteHeldHistory := range heldHistory {
if trustedSatellite.Compare(satelliteHeldHistory.SatelliteID) == 0 {
found = true
break
}
}
if !found {
heldHistory = append(heldHistory, HeldAmountHistory{
SatelliteID: trustedSatellite,
})
}
}
return heldHistory, nil
}
// parsePeriodRange creates period range form start and end periods.
// TODO: move to separate struct.
func parsePeriodRange(periodStart, periodEnd string) (periods []string, err error) {
var yearStart, yearEnd, monthStart, monthEnd int

View File

@ -1,43 +1,180 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package payouts
package payouts_test
import (
"context"
"errors"
"sync"
"testing"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"storj.io/common/identity"
"storj.io/common/storj"
"storj.io/common/testcontext"
"storj.io/common/testrand"
"storj.io/storj/storagenode"
"storj.io/storj/storagenode/payouts"
"storj.io/storj/storagenode/storagenodedb/storagenodedbtest"
"storj.io/storj/storagenode/trust"
)
func TestParsePeriodRange(t *testing.T) {
testCases := [...]struct {
periodStart string
periodEnd string
periods []string
}{
{"2020-01", "2020-02", []string{"2020-01", "2020-02"}},
{"2020-01", "2020-01", []string{"2020-01"}},
{"2019-11", "2020-02", []string{"2019-11", "2019-12", "2020-01", "2020-02"}},
{"", "2020-02", nil},
{"2020-01", "", nil},
{"2020-01-01", "2020-02", nil},
{"2020-44", "2020-02", nil},
{"2020-01", "2020-44", nil},
{"2020-01", "2019-01", nil},
{"2020-02", "2020-01", nil},
}
func TestServiceHeldAmountHistory(t *testing.T) {
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {
log := zaptest.NewLogger(t)
payoutsDB := db.Payout()
source := &fakeSource{}
pool, err := trust.NewPool(log, newFakeIdentityResolver(), trust.Config{
Sources: []trust.Source{source},
CachePath: ctx.File("trust-cache.json"),
})
require.NoError(t, err)
for _, tc := range testCases {
periods, err := parsePeriodRange(tc.periodStart, tc.periodEnd)
require.Equal(t, len(periods), len(tc.periods))
if periods != nil {
for i := 0; i < len(periods); i++ {
require.Equal(t, periods[i], tc.periods[i])
require.NoError(t, err)
}
} else {
require.Error(t, err)
satelliteID1 := testrand.NodeID()
satelliteID2 := testrand.NodeID()
satelliteID3 := testrand.NodeID()
// populate pool
source.entries = []trust.Entry{
{
SatelliteURL: trust.SatelliteURL{
ID: satelliteID1,
Host: "foo.test",
Port: 7777,
},
},
{
SatelliteURL: trust.SatelliteURL{
ID: satelliteID2,
Host: "bar.test",
Port: 7777,
},
},
{
SatelliteURL: trust.SatelliteURL{
ID: satelliteID3,
Host: "baz.test",
Port: 7777,
},
},
}
require.NoError(t, pool.Refresh(context.Background()))
// add paystubs
paystubs := []payouts.PayStub{
{
SatelliteID: satelliteID1,
Period: "2021-01",
Held: 10,
},
{
SatelliteID: satelliteID1,
Period: "2021-02",
Held: 10,
},
{
SatelliteID: satelliteID2,
Period: "2021-01",
Held: 0,
},
{
SatelliteID: satelliteID2,
Period: "2021-02",
Held: 0,
},
}
for _, paystub := range paystubs {
err = payoutsDB.StorePayStub(ctx, paystub)
require.NoError(t, err)
}
expected := []payouts.HeldAmountHistory{
{
SatelliteID: satelliteID1,
HeldAmounts: []payouts.HeldForPeriod{
{
Period: "2021-01",
Amount: 10,
},
{
Period: "2021-02",
Amount: 10,
},
},
},
{
SatelliteID: satelliteID2,
HeldAmounts: []payouts.HeldForPeriod{
{
Period: "2021-01",
Amount: 0,
},
{
Period: "2021-02",
Amount: 0,
},
},
},
{
SatelliteID: satelliteID3,
},
}
service, err := payouts.NewService(log, payoutsDB, db.Reputation(), db.Satellites(), pool)
require.NoError(t, err)
history, err := service.HeldAmountHistory(ctx)
require.NoError(t, err)
require.ElementsMatch(t, expected, history)
})
}
type fakeSource struct {
name string
static bool
entries []trust.Entry
err error
}
func (s *fakeSource) String() string {
return s.name
}
func (s *fakeSource) Static() bool {
return s.static
}
func (s *fakeSource) FetchEntries(context.Context) ([]trust.Entry, error) {
return s.entries, s.err
}
type fakeIdentityResolver struct {
mu sync.Mutex
identities map[storj.NodeURL]*identity.PeerIdentity
}
func newFakeIdentityResolver() *fakeIdentityResolver {
return &fakeIdentityResolver{
identities: make(map[storj.NodeURL]*identity.PeerIdentity),
}
}
func (resolver *fakeIdentityResolver) SetIdentity(url storj.NodeURL, identity *identity.PeerIdentity) {
resolver.mu.Lock()
defer resolver.mu.Unlock()
resolver.identities[url] = identity
}
func (resolver *fakeIdentityResolver) ResolveIdentity(ctx context.Context, url storj.NodeURL) (*identity.PeerIdentity, error) {
resolver.mu.Lock()
defer resolver.mu.Unlock()
identity := resolver.identities[url]
if identity == nil {
return nil, errors.New("no identity")
}
return identity, nil
}

View File

@ -563,8 +563,8 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten
debug.Cycle("Orders Cleanup", peer.Storage2.Orders.Cleanup))
}
{ // setup payouts service.
service, err := payouts.NewService(
{ // setup payouts.
peer.Payout.Service, err = payouts.NewService(
peer.Log.Named("payouts:service"),
peer.DB.Payout(),
peer.DB.Reputation(),
@ -574,7 +574,7 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten
if err != nil {
return nil, errs.Combine(err, peer.Close())
}
peer.Payout.Service = service
peer.Payout.Endpoint = payouts.NewEndpoint(
peer.Log.Named("payouts:endpoint"),
peer.Dialer,
@ -786,12 +786,14 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten
peer.Multinode.Storage = multinode.NewStorageEndpoint(
peer.Log.Named("multinode:storage-endpoint"),
apiKeys,
peer.Storage2.Monitor)
peer.Storage2.Monitor,
)
peer.Multinode.Bandwidth = multinode.NewBandwidthEndpoint(
peer.Log.Named("multinode:bandwidth-endpoint"),
apiKeys,
peer.DB.Bandwidth())
peer.DB.Bandwidth(),
)
peer.Multinode.Node = multinode.NewNodeEndpoint(
peer.Log.Named("multinode:node-endpoint"),
@ -799,13 +801,16 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten
peer.Version.Service.Info,
peer.Contact.PingStats,
peer.DB.Reputation(),
peer.Storage2.Trust)
peer.Storage2.Trust,
)
peer.Multinode.Payout = multinode.NewPayoutEndpoint(
peer.Log.Named("multinode:payout-endpoint"),
apiKeys,
peer.DB.Payout(),
peer.Estimation.Service,
peer.DB.Payout())
peer.Payout.Service,
)
if err = multinodepb.DRPCRegisterStorage(peer.Server.DRPC(), peer.Multinode.Storage); err != nil {
return nil, errs.Combine(err, peer.Close())

View File

@ -227,7 +227,7 @@ func (db *payoutDB) AllPayStubs(ctx context.Context, period string) (_ []payouts
}
// SatellitesHeldbackHistory retrieves heldback history for specific satellite.
func (db *payoutDB) SatellitesHeldbackHistory(ctx context.Context, id storj.NodeID) (_ []payouts.HoldForPeriod, err error) {
func (db *payoutDB) SatellitesHeldbackHistory(ctx context.Context, id storj.NodeID) (_ []payouts.HeldForPeriod, err error) {
defer mon.Task()(&ctx)(&err)
query := `SELECT
@ -242,9 +242,9 @@ func (db *payoutDB) SatellitesHeldbackHistory(ctx context.Context, id storj.Node
defer func() { err = errs.Combine(err, rows.Close()) }()
var heldback []payouts.HoldForPeriod
var heldback []payouts.HeldForPeriod
for rows.Next() {
var held payouts.HoldForPeriod
var held payouts.HeldForPeriod
err := rows.Scan(&held.Period, &held.Amount)
if err != nil {
@ -709,3 +709,56 @@ func (db *payoutDB) GetSatellitePeriodPaystubs(ctx context.Context, period strin
return &paystub, nil
}
// HeldAmountHistory retrieves held amount history for all satellites.
func (db *payoutDB) HeldAmountHistory(ctx context.Context) (_ []payouts.HeldAmountHistory, err error) {
defer mon.Task()(&ctx)(&err)
query := `
SELECT
satellite_id,
period,
held
FROM paystubs
ORDER BY satellite_id, period ASC`
rows, err := db.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer func() {
err = errs.Combine(err, rows.Close())
}()
cache := make(map[storj.NodeID]payouts.HeldAmountHistory)
for rows.Next() {
var idBytes []byte
var held payouts.HeldForPeriod
err := rows.Scan(&idBytes, &held.Period, &held.Amount)
if err != nil {
return nil, ErrPayout.Wrap(err)
}
satelliteID, err := storj.NodeIDFromBytes(idBytes)
if err != nil {
return nil, ErrPayout.Wrap(err)
}
satelliteHeldHistory := cache[satelliteID]
satelliteHeldHistory.HeldAmounts = append(satelliteHeldHistory.HeldAmounts, held)
cache[satelliteID] = satelliteHeldHistory
}
if err = rows.Err(); err != nil {
return nil, ErrPayout.Wrap(err)
}
var heldHistories []payouts.HeldAmountHistory
for satelliteID, heldHistory := range cache {
heldHistory.SatelliteID = satelliteID
heldHistories = append(heldHistories, heldHistory)
}
return heldHistories, nil
}