diff --git a/.gitignore b/.gitignore index 62ef9e850..8225821f5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Test binary, built with `go test -c` *.test +cover.out # Output of the go coverage tool, specifically when used with LiteIDE *.out diff --git a/Dockerfile b/Dockerfile index 2d650e628..652d46adb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN mkdir /app WORKDIR /app COPY go.mod go.sum ./ -RUN go mod download +RUN go mod download -x COPY . . RUN POW_BUILD_FLAGS="CGO_ENABLED=0 GOOS=linux" make build-powd RUN POW_BUILD_FLAGS="CGO_ENABLED=0 GOOS=linux" make build-pow diff --git a/api/client/admin/admin.go b/api/client/admin/admin.go index c33bfca14..766977d63 100644 --- a/api/client/admin/admin.go +++ b/api/client/admin/admin.go @@ -9,6 +9,7 @@ type Admin struct { StorageJobs *StorageJobs Users *Users Wallet *Wallet + Data *Data } // NewAdmin creates a new admin API. @@ -17,5 +18,6 @@ func NewAdmin(client adminPb.AdminServiceClient) *Admin { StorageJobs: &StorageJobs{client: client}, Users: &Users{client: client}, Wallet: &Wallet{client: client}, + Data: &Data{client: client}, } } diff --git a/api/client/admin/hs.go b/api/client/admin/hs.go new file mode 100644 index 000000000..ac82f5e39 --- /dev/null +++ b/api/client/admin/hs.go @@ -0,0 +1,22 @@ +package admin + +import ( + "context" + + proto "github.com/textileio/powergate/api/gen/powergate/admin/v1" +) + +// Data provides access to Powergate data admin APIs. +type Data struct { + client proto.AdminServiceClient +} + +// GCStaged unpins staged data not related to queued or executing jobs. +func (w *Data) GCStaged(ctx context.Context) (*proto.GCStagedResponse, error) { + return w.client.GCStaged(ctx, &proto.GCStagedRequest{}) +} + +// PinnedCids returns pinned cids information of hot-storage. +func (w *Data) PinnedCids(ctx context.Context) (*proto.PinnedCidsResponse, error) { + return w.client.PinnedCids(ctx, &proto.PinnedCidsRequest{}) +} diff --git a/api/client/data.go b/api/client/data.go index ab94afb4c..19310953c 100644 --- a/api/client/data.go +++ b/api/client/data.go @@ -97,13 +97,18 @@ func (d *Data) StageFolder(ctx context.Context, ipfsRevProxyAddr string, folderP defer func() { _ = ff.Close() }() opts := []options.UnixfsAddOption{ options.Unixfs.CidVersion(1), - options.Unixfs.Pin(false), + options.Unixfs.Pin(true), } pth, err := ipfs.Unixfs().Add(context.Background(), files.ToDir(ff), opts...) if err != nil { return "", err } + _, err = d.client.StageCid(ctx, &userPb.StageCidRequest{Cid: pth.Cid().String()}) + if err != nil { + return "", fmt.Errorf("stage pinning cid: %s", err) + } + return pth.Cid().String(), nil } diff --git a/api/client/utils_test.go b/api/client/utils_test.go index 8eea7df73..368336e6e 100644 --- a/api/client/utils_test.go +++ b/api/client/utils_test.go @@ -2,7 +2,6 @@ package client import ( "fmt" - "io/ioutil" "math/big" "testing" "time" @@ -25,9 +24,7 @@ func defaultServerConfig(t *testing.T) server.Config { gatewayHostAddr := fmt.Sprintf("0.0.0.0:%d", freePort(t)) indexRawJSONHostAddr := fmt.Sprintf("0.0.0.0:%d", freePort(t)) - repoPath, err := ioutil.TempDir("/tmp/powergate", ".powergate-*") - require.NoError(t, err) - + repoPath := t.TempDir() dipfs, cls := tests.LaunchIPFSDocker(t) t.Cleanup(func() { cls() }) @@ -56,6 +53,7 @@ func defaultServerConfig(t *testing.T) server.Config { MinerSelector: "reputation", FFSDealFinalityTimeout: time.Minute * 30, FFSMaxParallelDealPreparing: 1, + FFSGCAutomaticGCInterval: 0, DealWatchPollDuration: time.Second * 15, SchedMaxParallel: 10, AskIndexQueryAskTimeout: time.Second * 3, diff --git a/api/gen/powergate/admin/v1/admin.pb.go b/api/gen/powergate/admin/v1/admin.pb.go index dd25df694..a7b17bb52 100644 --- a/api/gen/powergate/admin/v1/admin.pb.go +++ b/api/gen/powergate/admin/v1/admin.pb.go @@ -1074,6 +1074,294 @@ func (x *StorageJobsSummaryResponse) GetLatestSuccessfulStorageJobs() []*v1.Stor return nil } +type GCStagedRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GCStagedRequest) Reset() { + *x = GCStagedRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCStagedRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCStagedRequest) ProtoMessage() {} + +func (x *GCStagedRequest) ProtoReflect() protoreflect.Message { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCStagedRequest.ProtoReflect.Descriptor instead. +func (*GCStagedRequest) Descriptor() ([]byte, []int) { + return file_powergate_admin_v1_admin_proto_rawDescGZIP(), []int{21} +} + +type GCStagedResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UnpinnedCids []string `protobuf:"bytes,1,rep,name=unpinned_cids,json=unpinnedCids,proto3" json:"unpinned_cids,omitempty"` +} + +func (x *GCStagedResponse) Reset() { + *x = GCStagedResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCStagedResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCStagedResponse) ProtoMessage() {} + +func (x *GCStagedResponse) ProtoReflect() protoreflect.Message { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCStagedResponse.ProtoReflect.Descriptor instead. +func (*GCStagedResponse) Descriptor() ([]byte, []int) { + return file_powergate_admin_v1_admin_proto_rawDescGZIP(), []int{22} +} + +func (x *GCStagedResponse) GetUnpinnedCids() []string { + if x != nil { + return x.UnpinnedCids + } + return nil +} + +type PinnedCidsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PinnedCidsRequest) Reset() { + *x = PinnedCidsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PinnedCidsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PinnedCidsRequest) ProtoMessage() {} + +func (x *PinnedCidsRequest) ProtoReflect() protoreflect.Message { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PinnedCidsRequest.ProtoReflect.Descriptor instead. +func (*PinnedCidsRequest) Descriptor() ([]byte, []int) { + return file_powergate_admin_v1_admin_proto_rawDescGZIP(), []int{23} +} + +type PinnedCidsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cids []*HSPinnedCid `protobuf:"bytes,1,rep,name=cids,proto3" json:"cids,omitempty"` +} + +func (x *PinnedCidsResponse) Reset() { + *x = PinnedCidsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PinnedCidsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PinnedCidsResponse) ProtoMessage() {} + +func (x *PinnedCidsResponse) ProtoReflect() protoreflect.Message { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PinnedCidsResponse.ProtoReflect.Descriptor instead. +func (*PinnedCidsResponse) Descriptor() ([]byte, []int) { + return file_powergate_admin_v1_admin_proto_rawDescGZIP(), []int{24} +} + +func (x *PinnedCidsResponse) GetCids() []*HSPinnedCid { + if x != nil { + return x.Cids + } + return nil +} + +type HSPinnedCid struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"` + Users []*HSPinnedCidUser `protobuf:"bytes,2,rep,name=users,proto3" json:"users,omitempty"` +} + +func (x *HSPinnedCid) Reset() { + *x = HSPinnedCid{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HSPinnedCid) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HSPinnedCid) ProtoMessage() {} + +func (x *HSPinnedCid) ProtoReflect() protoreflect.Message { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HSPinnedCid.ProtoReflect.Descriptor instead. +func (*HSPinnedCid) Descriptor() ([]byte, []int) { + return file_powergate_admin_v1_admin_proto_rawDescGZIP(), []int{25} +} + +func (x *HSPinnedCid) GetCid() string { + if x != nil { + return x.Cid + } + return "" +} + +func (x *HSPinnedCid) GetUsers() []*HSPinnedCidUser { + if x != nil { + return x.Users + } + return nil +} + +type HSPinnedCidUser struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Staged bool `protobuf:"varint,2,opt,name=staged,proto3" json:"staged,omitempty"` + CreatedAt int64 `protobuf:"varint,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` +} + +func (x *HSPinnedCidUser) Reset() { + *x = HSPinnedCidUser{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HSPinnedCidUser) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HSPinnedCidUser) ProtoMessage() {} + +func (x *HSPinnedCidUser) ProtoReflect() protoreflect.Message { + mi := &file_powergate_admin_v1_admin_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HSPinnedCidUser.ProtoReflect.Descriptor instead. +func (*HSPinnedCidUser) Descriptor() ([]byte, []int) { + return file_powergate_admin_v1_admin_proto_rawDescGZIP(), []int{26} +} + +func (x *HSPinnedCidUser) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *HSPinnedCidUser) GetStaged() bool { + if x != nil { + return x.Staged + } + return false +} + +func (x *HSPinnedCidUser) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + var File_powergate_admin_v1_admin_proto protoreflect.FileDescriptor var file_powergate_admin_v1_admin_proto_rawDesc = []byte{ @@ -1189,81 +1477,115 @@ var file_powergate_admin_v1_admin_proto_rawDesc = []byte{ 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x1b, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x32, 0xcd, 0x08, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, + 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x47, 0x43, 0x53, 0x74, 0x61, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x37, 0x0a, 0x10, 0x47, 0x43, 0x53, + 0x74, 0x61, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x75, 0x6e, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x75, 0x6e, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, + 0x64, 0x73, 0x22, 0x13, 0x0a, 0x11, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x6e, 0x65, + 0x64, 0x43, 0x69, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, + 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x6f, + 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x48, 0x53, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, 0x64, 0x52, 0x04, 0x63, 0x69, + 0x64, 0x73, 0x22, 0x5a, 0x0a, 0x0b, 0x48, 0x53, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, + 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x63, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x53, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, + 0x43, 0x69, 0x64, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x61, + 0x0a, 0x0f, 0x48, 0x53, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, 0x64, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, 0x61, 0x67, + 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x32, 0x85, 0x0a, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x65, 0x77, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x24, + 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, + 0x07, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x12, 0x22, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, - 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x54, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x12, 0x22, 0x2e, + 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x20, 0x2e, 0x70, 0x6f, + 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x72, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x2c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, + 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, + 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7b, 0x0a, 0x14, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x2f, + 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x30, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x16, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, + 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x31, + 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x32, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, + 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, 0x1b, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x36, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x37, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x75, 0x0a, 0x12, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x12, 0x2d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, + 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2e, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, + 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x57, 0x0a, 0x08, 0x47, 0x43, 0x53, 0x74, 0x61, 0x67, 0x65, 0x64, 0x12, 0x23, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x12, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x72, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x75, 0x65, - 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x2c, 0x2e, 0x70, - 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x70, 0x6f, 0x77, - 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7b, 0x0a, 0x14, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x73, 0x12, 0x2f, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x16, 0x4c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x73, 0x12, 0x31, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, - 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, 0x01, 0x0a, - 0x1b, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, - 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x36, 0x2e, 0x70, - 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, - 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x75, 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6c, 0x65, 0x69, 0x6f, 0x2f, 0x70, - 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, - 0x2f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x47, 0x43, 0x53, 0x74, 0x61, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x43, 0x53, 0x74, 0x61, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x50, 0x69, + 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, 0x64, 0x73, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, + 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x69, 0x64, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6c, 0x65, 0x69, + 0x6f, 0x2f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1278,7 +1600,7 @@ func file_powergate_admin_v1_admin_proto_rawDescGZIP() []byte { return file_powergate_admin_v1_admin_proto_rawDescData } -var file_powergate_admin_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_powergate_admin_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_powergate_admin_v1_admin_proto_goTypes = []interface{}{ (*NewAddressRequest)(nil), // 0: powergate.admin.v1.NewAddressRequest (*NewAddressResponse)(nil), // 1: powergate.admin.v1.NewAddressResponse @@ -1301,46 +1623,58 @@ var file_powergate_admin_v1_admin_proto_goTypes = []interface{}{ (*LatestSuccessfulStorageJobsResponse)(nil), // 18: powergate.admin.v1.LatestSuccessfulStorageJobsResponse (*StorageJobsSummaryRequest)(nil), // 19: powergate.admin.v1.StorageJobsSummaryRequest (*StorageJobsSummaryResponse)(nil), // 20: powergate.admin.v1.StorageJobsSummaryResponse - (*v1.StorageJob)(nil), // 21: powergate.user.v1.StorageJob - (*v1.JobCounts)(nil), // 22: powergate.user.v1.JobCounts + (*GCStagedRequest)(nil), // 21: powergate.admin.v1.GCStagedRequest + (*GCStagedResponse)(nil), // 22: powergate.admin.v1.GCStagedResponse + (*PinnedCidsRequest)(nil), // 23: powergate.admin.v1.PinnedCidsRequest + (*PinnedCidsResponse)(nil), // 24: powergate.admin.v1.PinnedCidsResponse + (*HSPinnedCid)(nil), // 25: powergate.admin.v1.HSPinnedCid + (*HSPinnedCidUser)(nil), // 26: powergate.admin.v1.HSPinnedCidUser + (*v1.StorageJob)(nil), // 27: powergate.user.v1.StorageJob + (*v1.JobCounts)(nil), // 28: powergate.user.v1.JobCounts } var file_powergate_admin_v1_admin_proto_depIdxs = []int32{ 6, // 0: powergate.admin.v1.CreateUserResponse.user:type_name -> powergate.admin.v1.User 6, // 1: powergate.admin.v1.UsersResponse.users:type_name -> powergate.admin.v1.User - 21, // 2: powergate.admin.v1.QueuedStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 21, // 3: powergate.admin.v1.ExecutingStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 21, // 4: powergate.admin.v1.LatestFinalStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 21, // 5: powergate.admin.v1.LatestSuccessfulStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 22, // 6: powergate.admin.v1.StorageJobsSummaryResponse.job_counts:type_name -> powergate.user.v1.JobCounts - 21, // 7: powergate.admin.v1.StorageJobsSummaryResponse.queued_storage_jobs:type_name -> powergate.user.v1.StorageJob - 21, // 8: powergate.admin.v1.StorageJobsSummaryResponse.executing_storage_jobs:type_name -> powergate.user.v1.StorageJob - 21, // 9: powergate.admin.v1.StorageJobsSummaryResponse.latest_final_storage_jobs:type_name -> powergate.user.v1.StorageJob - 21, // 10: powergate.admin.v1.StorageJobsSummaryResponse.latest_successful_storage_jobs:type_name -> powergate.user.v1.StorageJob - 0, // 11: powergate.admin.v1.AdminService.NewAddress:input_type -> powergate.admin.v1.NewAddressRequest - 2, // 12: powergate.admin.v1.AdminService.Addresses:input_type -> powergate.admin.v1.AddressesRequest - 4, // 13: powergate.admin.v1.AdminService.SendFil:input_type -> powergate.admin.v1.SendFilRequest - 7, // 14: powergate.admin.v1.AdminService.CreateUser:input_type -> powergate.admin.v1.CreateUserRequest - 9, // 15: powergate.admin.v1.AdminService.Users:input_type -> powergate.admin.v1.UsersRequest - 11, // 16: powergate.admin.v1.AdminService.QueuedStorageJobs:input_type -> powergate.admin.v1.QueuedStorageJobsRequest - 13, // 17: powergate.admin.v1.AdminService.ExecutingStorageJobs:input_type -> powergate.admin.v1.ExecutingStorageJobsRequest - 15, // 18: powergate.admin.v1.AdminService.LatestFinalStorageJobs:input_type -> powergate.admin.v1.LatestFinalStorageJobsRequest - 17, // 19: powergate.admin.v1.AdminService.LatestSuccessfulStorageJobs:input_type -> powergate.admin.v1.LatestSuccessfulStorageJobsRequest - 19, // 20: powergate.admin.v1.AdminService.StorageJobsSummary:input_type -> powergate.admin.v1.StorageJobsSummaryRequest - 1, // 21: powergate.admin.v1.AdminService.NewAddress:output_type -> powergate.admin.v1.NewAddressResponse - 3, // 22: powergate.admin.v1.AdminService.Addresses:output_type -> powergate.admin.v1.AddressesResponse - 5, // 23: powergate.admin.v1.AdminService.SendFil:output_type -> powergate.admin.v1.SendFilResponse - 8, // 24: powergate.admin.v1.AdminService.CreateUser:output_type -> powergate.admin.v1.CreateUserResponse - 10, // 25: powergate.admin.v1.AdminService.Users:output_type -> powergate.admin.v1.UsersResponse - 12, // 26: powergate.admin.v1.AdminService.QueuedStorageJobs:output_type -> powergate.admin.v1.QueuedStorageJobsResponse - 14, // 27: powergate.admin.v1.AdminService.ExecutingStorageJobs:output_type -> powergate.admin.v1.ExecutingStorageJobsResponse - 16, // 28: powergate.admin.v1.AdminService.LatestFinalStorageJobs:output_type -> powergate.admin.v1.LatestFinalStorageJobsResponse - 18, // 29: powergate.admin.v1.AdminService.LatestSuccessfulStorageJobs:output_type -> powergate.admin.v1.LatestSuccessfulStorageJobsResponse - 20, // 30: powergate.admin.v1.AdminService.StorageJobsSummary:output_type -> powergate.admin.v1.StorageJobsSummaryResponse - 21, // [21:31] is the sub-list for method output_type - 11, // [11:21] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 27, // 2: powergate.admin.v1.QueuedStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 27, // 3: powergate.admin.v1.ExecutingStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 27, // 4: powergate.admin.v1.LatestFinalStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 27, // 5: powergate.admin.v1.LatestSuccessfulStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 28, // 6: powergate.admin.v1.StorageJobsSummaryResponse.job_counts:type_name -> powergate.user.v1.JobCounts + 27, // 7: powergate.admin.v1.StorageJobsSummaryResponse.queued_storage_jobs:type_name -> powergate.user.v1.StorageJob + 27, // 8: powergate.admin.v1.StorageJobsSummaryResponse.executing_storage_jobs:type_name -> powergate.user.v1.StorageJob + 27, // 9: powergate.admin.v1.StorageJobsSummaryResponse.latest_final_storage_jobs:type_name -> powergate.user.v1.StorageJob + 27, // 10: powergate.admin.v1.StorageJobsSummaryResponse.latest_successful_storage_jobs:type_name -> powergate.user.v1.StorageJob + 25, // 11: powergate.admin.v1.PinnedCidsResponse.cids:type_name -> powergate.admin.v1.HSPinnedCid + 26, // 12: powergate.admin.v1.HSPinnedCid.users:type_name -> powergate.admin.v1.HSPinnedCidUser + 0, // 13: powergate.admin.v1.AdminService.NewAddress:input_type -> powergate.admin.v1.NewAddressRequest + 2, // 14: powergate.admin.v1.AdminService.Addresses:input_type -> powergate.admin.v1.AddressesRequest + 4, // 15: powergate.admin.v1.AdminService.SendFil:input_type -> powergate.admin.v1.SendFilRequest + 7, // 16: powergate.admin.v1.AdminService.CreateUser:input_type -> powergate.admin.v1.CreateUserRequest + 9, // 17: powergate.admin.v1.AdminService.Users:input_type -> powergate.admin.v1.UsersRequest + 11, // 18: powergate.admin.v1.AdminService.QueuedStorageJobs:input_type -> powergate.admin.v1.QueuedStorageJobsRequest + 13, // 19: powergate.admin.v1.AdminService.ExecutingStorageJobs:input_type -> powergate.admin.v1.ExecutingStorageJobsRequest + 15, // 20: powergate.admin.v1.AdminService.LatestFinalStorageJobs:input_type -> powergate.admin.v1.LatestFinalStorageJobsRequest + 17, // 21: powergate.admin.v1.AdminService.LatestSuccessfulStorageJobs:input_type -> powergate.admin.v1.LatestSuccessfulStorageJobsRequest + 19, // 22: powergate.admin.v1.AdminService.StorageJobsSummary:input_type -> powergate.admin.v1.StorageJobsSummaryRequest + 21, // 23: powergate.admin.v1.AdminService.GCStaged:input_type -> powergate.admin.v1.GCStagedRequest + 23, // 24: powergate.admin.v1.AdminService.PinnedCids:input_type -> powergate.admin.v1.PinnedCidsRequest + 1, // 25: powergate.admin.v1.AdminService.NewAddress:output_type -> powergate.admin.v1.NewAddressResponse + 3, // 26: powergate.admin.v1.AdminService.Addresses:output_type -> powergate.admin.v1.AddressesResponse + 5, // 27: powergate.admin.v1.AdminService.SendFil:output_type -> powergate.admin.v1.SendFilResponse + 8, // 28: powergate.admin.v1.AdminService.CreateUser:output_type -> powergate.admin.v1.CreateUserResponse + 10, // 29: powergate.admin.v1.AdminService.Users:output_type -> powergate.admin.v1.UsersResponse + 12, // 30: powergate.admin.v1.AdminService.QueuedStorageJobs:output_type -> powergate.admin.v1.QueuedStorageJobsResponse + 14, // 31: powergate.admin.v1.AdminService.ExecutingStorageJobs:output_type -> powergate.admin.v1.ExecutingStorageJobsResponse + 16, // 32: powergate.admin.v1.AdminService.LatestFinalStorageJobs:output_type -> powergate.admin.v1.LatestFinalStorageJobsResponse + 18, // 33: powergate.admin.v1.AdminService.LatestSuccessfulStorageJobs:output_type -> powergate.admin.v1.LatestSuccessfulStorageJobsResponse + 20, // 34: powergate.admin.v1.AdminService.StorageJobsSummary:output_type -> powergate.admin.v1.StorageJobsSummaryResponse + 22, // 35: powergate.admin.v1.AdminService.GCStaged:output_type -> powergate.admin.v1.GCStagedResponse + 24, // 36: powergate.admin.v1.AdminService.PinnedCids:output_type -> powergate.admin.v1.PinnedCidsResponse + 25, // [25:37] is the sub-list for method output_type + 13, // [13:25] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_powergate_admin_v1_admin_proto_init() } @@ -1601,6 +1935,78 @@ func file_powergate_admin_v1_admin_proto_init() { return nil } } + file_powergate_admin_v1_admin_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCStagedRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_admin_v1_admin_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCStagedResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_admin_v1_admin_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinnedCidsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_admin_v1_admin_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinnedCidsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_admin_v1_admin_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HSPinnedCid); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_admin_v1_admin_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HSPinnedCidUser); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1608,7 +2014,7 @@ func file_powergate_admin_v1_admin_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_powergate_admin_v1_admin_proto_rawDesc, NumEnums: 0, - NumMessages: 21, + NumMessages: 27, NumExtensions: 0, NumServices: 1, }, diff --git a/api/gen/powergate/admin/v1/admin_grpc.pb.go b/api/gen/powergate/admin/v1/admin_grpc.pb.go index b6415c7dc..21c60a1e5 100644 --- a/api/gen/powergate/admin/v1/admin_grpc.pb.go +++ b/api/gen/powergate/admin/v1/admin_grpc.pb.go @@ -30,6 +30,8 @@ type AdminServiceClient interface { LatestFinalStorageJobs(ctx context.Context, in *LatestFinalStorageJobsRequest, opts ...grpc.CallOption) (*LatestFinalStorageJobsResponse, error) LatestSuccessfulStorageJobs(ctx context.Context, in *LatestSuccessfulStorageJobsRequest, opts ...grpc.CallOption) (*LatestSuccessfulStorageJobsResponse, error) StorageJobsSummary(ctx context.Context, in *StorageJobsSummaryRequest, opts ...grpc.CallOption) (*StorageJobsSummaryResponse, error) + GCStaged(ctx context.Context, in *GCStagedRequest, opts ...grpc.CallOption) (*GCStagedResponse, error) + PinnedCids(ctx context.Context, in *PinnedCidsRequest, opts ...grpc.CallOption) (*PinnedCidsResponse, error) } type adminServiceClient struct { @@ -130,6 +132,24 @@ func (c *adminServiceClient) StorageJobsSummary(ctx context.Context, in *Storage return out, nil } +func (c *adminServiceClient) GCStaged(ctx context.Context, in *GCStagedRequest, opts ...grpc.CallOption) (*GCStagedResponse, error) { + out := new(GCStagedResponse) + err := c.cc.Invoke(ctx, "/powergate.admin.v1.AdminService/GCStaged", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) PinnedCids(ctx context.Context, in *PinnedCidsRequest, opts ...grpc.CallOption) (*PinnedCidsResponse, error) { + out := new(PinnedCidsResponse) + err := c.cc.Invoke(ctx, "/powergate.admin.v1.AdminService/PinnedCids", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AdminServiceServer is the server API for AdminService service. // All implementations must embed UnimplementedAdminServiceServer // for forward compatibility @@ -147,6 +167,8 @@ type AdminServiceServer interface { LatestFinalStorageJobs(context.Context, *LatestFinalStorageJobsRequest) (*LatestFinalStorageJobsResponse, error) LatestSuccessfulStorageJobs(context.Context, *LatestSuccessfulStorageJobsRequest) (*LatestSuccessfulStorageJobsResponse, error) StorageJobsSummary(context.Context, *StorageJobsSummaryRequest) (*StorageJobsSummaryResponse, error) + GCStaged(context.Context, *GCStagedRequest) (*GCStagedResponse, error) + PinnedCids(context.Context, *PinnedCidsRequest) (*PinnedCidsResponse, error) mustEmbedUnimplementedAdminServiceServer() } @@ -184,6 +206,12 @@ func (UnimplementedAdminServiceServer) LatestSuccessfulStorageJobs(context.Conte func (UnimplementedAdminServiceServer) StorageJobsSummary(context.Context, *StorageJobsSummaryRequest) (*StorageJobsSummaryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method StorageJobsSummary not implemented") } +func (UnimplementedAdminServiceServer) GCStaged(context.Context, *GCStagedRequest) (*GCStagedResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GCStaged not implemented") +} +func (UnimplementedAdminServiceServer) PinnedCids(context.Context, *PinnedCidsRequest) (*PinnedCidsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PinnedCids not implemented") +} func (UnimplementedAdminServiceServer) mustEmbedUnimplementedAdminServiceServer() {} // UnsafeAdminServiceServer may be embedded to opt out of forward compatibility for this service. @@ -377,6 +405,42 @@ func _AdminService_StorageJobsSummary_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _AdminService_GCStaged_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GCStagedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).GCStaged(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/powergate.admin.v1.AdminService/GCStaged", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).GCStaged(ctx, req.(*GCStagedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_PinnedCids_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PinnedCidsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).PinnedCids(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/powergate.admin.v1.AdminService/PinnedCids", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).PinnedCids(ctx, req.(*PinnedCidsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _AdminService_serviceDesc = grpc.ServiceDesc{ ServiceName: "powergate.admin.v1.AdminService", HandlerType: (*AdminServiceServer)(nil), @@ -421,6 +485,14 @@ var _AdminService_serviceDesc = grpc.ServiceDesc{ MethodName: "StorageJobsSummary", Handler: _AdminService_StorageJobsSummary_Handler, }, + { + MethodName: "GCStaged", + Handler: _AdminService_GCStaged_Handler, + }, + { + MethodName: "PinnedCids", + Handler: _AdminService_PinnedCids_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "powergate/admin/v1/admin.proto", diff --git a/api/gen/powergate/user/v1/user.pb.go b/api/gen/powergate/user/v1/user.pb.go index 949388c85..c15f533de 100644 --- a/api/gen/powergate/user/v1/user.pb.go +++ b/api/gen/powergate/user/v1/user.pb.go @@ -557,6 +557,91 @@ func (x *StageResponse) GetCid() string { return "" } +type StageCidRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"` +} + +func (x *StageCidRequest) Reset() { + *x = StageCidRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_user_v1_user_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StageCidRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StageCidRequest) ProtoMessage() {} + +func (x *StageCidRequest) ProtoReflect() protoreflect.Message { + mi := &file_powergate_user_v1_user_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StageCidRequest.ProtoReflect.Descriptor instead. +func (*StageCidRequest) Descriptor() ([]byte, []int) { + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{10} +} + +func (x *StageCidRequest) GetCid() string { + if x != nil { + return x.Cid + } + return "" +} + +type StageCidResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StageCidResponse) Reset() { + *x = StageCidResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_powergate_user_v1_user_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StageCidResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StageCidResponse) ProtoMessage() {} + +func (x *StageCidResponse) ProtoReflect() protoreflect.Message { + mi := &file_powergate_user_v1_user_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StageCidResponse.ProtoReflect.Descriptor instead. +func (*StageCidResponse) Descriptor() ([]byte, []int) { + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{11} +} + type ApplyStorageConfigRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -572,7 +657,7 @@ type ApplyStorageConfigRequest struct { func (x *ApplyStorageConfigRequest) Reset() { *x = ApplyStorageConfigRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[10] + mi := &file_powergate_user_v1_user_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -585,7 +670,7 @@ func (x *ApplyStorageConfigRequest) String() string { func (*ApplyStorageConfigRequest) ProtoMessage() {} func (x *ApplyStorageConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[10] + mi := &file_powergate_user_v1_user_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -598,7 +683,7 @@ func (x *ApplyStorageConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyStorageConfigRequest.ProtoReflect.Descriptor instead. func (*ApplyStorageConfigRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{10} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{12} } func (x *ApplyStorageConfigRequest) GetCid() string { @@ -647,7 +732,7 @@ type ApplyStorageConfigResponse struct { func (x *ApplyStorageConfigResponse) Reset() { *x = ApplyStorageConfigResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[11] + mi := &file_powergate_user_v1_user_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -660,7 +745,7 @@ func (x *ApplyStorageConfigResponse) String() string { func (*ApplyStorageConfigResponse) ProtoMessage() {} func (x *ApplyStorageConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[11] + mi := &file_powergate_user_v1_user_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -673,7 +758,7 @@ func (x *ApplyStorageConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyStorageConfigResponse.ProtoReflect.Descriptor instead. func (*ApplyStorageConfigResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{11} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{13} } func (x *ApplyStorageConfigResponse) GetJobId() string { @@ -695,7 +780,7 @@ type ReplaceDataRequest struct { func (x *ReplaceDataRequest) Reset() { *x = ReplaceDataRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[12] + mi := &file_powergate_user_v1_user_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -708,7 +793,7 @@ func (x *ReplaceDataRequest) String() string { func (*ReplaceDataRequest) ProtoMessage() {} func (x *ReplaceDataRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[12] + mi := &file_powergate_user_v1_user_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -721,7 +806,7 @@ func (x *ReplaceDataRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplaceDataRequest.ProtoReflect.Descriptor instead. func (*ReplaceDataRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{12} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{14} } func (x *ReplaceDataRequest) GetCid1() string { @@ -749,7 +834,7 @@ type ReplaceDataResponse struct { func (x *ReplaceDataResponse) Reset() { *x = ReplaceDataResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[13] + mi := &file_powergate_user_v1_user_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -762,7 +847,7 @@ func (x *ReplaceDataResponse) String() string { func (*ReplaceDataResponse) ProtoMessage() {} func (x *ReplaceDataResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[13] + mi := &file_powergate_user_v1_user_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -775,7 +860,7 @@ func (x *ReplaceDataResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplaceDataResponse.ProtoReflect.Descriptor instead. func (*ReplaceDataResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{13} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{15} } func (x *ReplaceDataResponse) GetJobId() string { @@ -796,7 +881,7 @@ type GetRequest struct { func (x *GetRequest) Reset() { *x = GetRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[14] + mi := &file_powergate_user_v1_user_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -809,7 +894,7 @@ func (x *GetRequest) String() string { func (*GetRequest) ProtoMessage() {} func (x *GetRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[14] + mi := &file_powergate_user_v1_user_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -822,7 +907,7 @@ func (x *GetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRequest.ProtoReflect.Descriptor instead. func (*GetRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{14} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{16} } func (x *GetRequest) GetCid() string { @@ -843,7 +928,7 @@ type GetResponse struct { func (x *GetResponse) Reset() { *x = GetResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[15] + mi := &file_powergate_user_v1_user_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -856,7 +941,7 @@ func (x *GetResponse) String() string { func (*GetResponse) ProtoMessage() {} func (x *GetResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[15] + mi := &file_powergate_user_v1_user_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -869,7 +954,7 @@ func (x *GetResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetResponse.ProtoReflect.Descriptor instead. func (*GetResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{15} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{17} } func (x *GetResponse) GetChunk() []byte { @@ -890,7 +975,7 @@ type RemoveRequest struct { func (x *RemoveRequest) Reset() { *x = RemoveRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[16] + mi := &file_powergate_user_v1_user_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -903,7 +988,7 @@ func (x *RemoveRequest) String() string { func (*RemoveRequest) ProtoMessage() {} func (x *RemoveRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[16] + mi := &file_powergate_user_v1_user_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -916,7 +1001,7 @@ func (x *RemoveRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveRequest.ProtoReflect.Descriptor instead. func (*RemoveRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{16} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{18} } func (x *RemoveRequest) GetCid() string { @@ -935,7 +1020,7 @@ type RemoveResponse struct { func (x *RemoveResponse) Reset() { *x = RemoveResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[17] + mi := &file_powergate_user_v1_user_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -948,7 +1033,7 @@ func (x *RemoveResponse) String() string { func (*RemoveResponse) ProtoMessage() {} func (x *RemoveResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[17] + mi := &file_powergate_user_v1_user_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -961,7 +1046,7 @@ func (x *RemoveResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveResponse.ProtoReflect.Descriptor instead. func (*RemoveResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{17} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{19} } type WatchLogsRequest struct { @@ -977,7 +1062,7 @@ type WatchLogsRequest struct { func (x *WatchLogsRequest) Reset() { *x = WatchLogsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[18] + mi := &file_powergate_user_v1_user_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -990,7 +1075,7 @@ func (x *WatchLogsRequest) String() string { func (*WatchLogsRequest) ProtoMessage() {} func (x *WatchLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[18] + mi := &file_powergate_user_v1_user_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1003,7 +1088,7 @@ func (x *WatchLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchLogsRequest.ProtoReflect.Descriptor instead. func (*WatchLogsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{18} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{20} } func (x *WatchLogsRequest) GetCid() string { @@ -1038,7 +1123,7 @@ type WatchLogsResponse struct { func (x *WatchLogsResponse) Reset() { *x = WatchLogsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[19] + mi := &file_powergate_user_v1_user_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1051,7 +1136,7 @@ func (x *WatchLogsResponse) String() string { func (*WatchLogsResponse) ProtoMessage() {} func (x *WatchLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[19] + mi := &file_powergate_user_v1_user_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1064,7 +1149,7 @@ func (x *WatchLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchLogsResponse.ProtoReflect.Descriptor instead. func (*WatchLogsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{19} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{21} } func (x *WatchLogsResponse) GetLogEntry() *LogEntry { @@ -1085,7 +1170,7 @@ type CidInfoRequest struct { func (x *CidInfoRequest) Reset() { *x = CidInfoRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[20] + mi := &file_powergate_user_v1_user_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1098,7 +1183,7 @@ func (x *CidInfoRequest) String() string { func (*CidInfoRequest) ProtoMessage() {} func (x *CidInfoRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[20] + mi := &file_powergate_user_v1_user_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1111,7 +1196,7 @@ func (x *CidInfoRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CidInfoRequest.ProtoReflect.Descriptor instead. func (*CidInfoRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{20} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{22} } func (x *CidInfoRequest) GetCids() []string { @@ -1132,7 +1217,7 @@ type CidInfoResponse struct { func (x *CidInfoResponse) Reset() { *x = CidInfoResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[21] + mi := &file_powergate_user_v1_user_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1145,7 +1230,7 @@ func (x *CidInfoResponse) String() string { func (*CidInfoResponse) ProtoMessage() {} func (x *CidInfoResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[21] + mi := &file_powergate_user_v1_user_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1158,7 +1243,7 @@ func (x *CidInfoResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CidInfoResponse.ProtoReflect.Descriptor instead. func (*CidInfoResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{21} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{23} } func (x *CidInfoResponse) GetCidInfos() []*CidInfo { @@ -1179,7 +1264,7 @@ type BalanceRequest struct { func (x *BalanceRequest) Reset() { *x = BalanceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[22] + mi := &file_powergate_user_v1_user_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1192,7 +1277,7 @@ func (x *BalanceRequest) String() string { func (*BalanceRequest) ProtoMessage() {} func (x *BalanceRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[22] + mi := &file_powergate_user_v1_user_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1205,7 +1290,7 @@ func (x *BalanceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BalanceRequest.ProtoReflect.Descriptor instead. func (*BalanceRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{22} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{24} } func (x *BalanceRequest) GetAddress() string { @@ -1226,7 +1311,7 @@ type BalanceResponse struct { func (x *BalanceResponse) Reset() { *x = BalanceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[23] + mi := &file_powergate_user_v1_user_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1239,7 +1324,7 @@ func (x *BalanceResponse) String() string { func (*BalanceResponse) ProtoMessage() {} func (x *BalanceResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[23] + mi := &file_powergate_user_v1_user_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1252,7 +1337,7 @@ func (x *BalanceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BalanceResponse.ProtoReflect.Descriptor instead. func (*BalanceResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{23} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{25} } func (x *BalanceResponse) GetBalance() string { @@ -1275,7 +1360,7 @@ type NewAddressRequest struct { func (x *NewAddressRequest) Reset() { *x = NewAddressRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[24] + mi := &file_powergate_user_v1_user_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1288,7 +1373,7 @@ func (x *NewAddressRequest) String() string { func (*NewAddressRequest) ProtoMessage() {} func (x *NewAddressRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[24] + mi := &file_powergate_user_v1_user_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1301,7 +1386,7 @@ func (x *NewAddressRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use NewAddressRequest.ProtoReflect.Descriptor instead. func (*NewAddressRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{24} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{26} } func (x *NewAddressRequest) GetName() string { @@ -1336,7 +1421,7 @@ type NewAddressResponse struct { func (x *NewAddressResponse) Reset() { *x = NewAddressResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[25] + mi := &file_powergate_user_v1_user_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1349,7 +1434,7 @@ func (x *NewAddressResponse) String() string { func (*NewAddressResponse) ProtoMessage() {} func (x *NewAddressResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[25] + mi := &file_powergate_user_v1_user_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1362,7 +1447,7 @@ func (x *NewAddressResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use NewAddressResponse.ProtoReflect.Descriptor instead. func (*NewAddressResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{25} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{27} } func (x *NewAddressResponse) GetAddress() string { @@ -1381,7 +1466,7 @@ type AddressesRequest struct { func (x *AddressesRequest) Reset() { *x = AddressesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[26] + mi := &file_powergate_user_v1_user_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1394,7 +1479,7 @@ func (x *AddressesRequest) String() string { func (*AddressesRequest) ProtoMessage() {} func (x *AddressesRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[26] + mi := &file_powergate_user_v1_user_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1407,7 +1492,7 @@ func (x *AddressesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddressesRequest.ProtoReflect.Descriptor instead. func (*AddressesRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{26} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{28} } type AddressesResponse struct { @@ -1421,7 +1506,7 @@ type AddressesResponse struct { func (x *AddressesResponse) Reset() { *x = AddressesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[27] + mi := &file_powergate_user_v1_user_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1434,7 +1519,7 @@ func (x *AddressesResponse) String() string { func (*AddressesResponse) ProtoMessage() {} func (x *AddressesResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[27] + mi := &file_powergate_user_v1_user_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1447,7 +1532,7 @@ func (x *AddressesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddressesResponse.ProtoReflect.Descriptor instead. func (*AddressesResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{27} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{29} } func (x *AddressesResponse) GetAddresses() []*AddrInfo { @@ -1470,7 +1555,7 @@ type SendFilRequest struct { func (x *SendFilRequest) Reset() { *x = SendFilRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[28] + mi := &file_powergate_user_v1_user_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1483,7 +1568,7 @@ func (x *SendFilRequest) String() string { func (*SendFilRequest) ProtoMessage() {} func (x *SendFilRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[28] + mi := &file_powergate_user_v1_user_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1496,7 +1581,7 @@ func (x *SendFilRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendFilRequest.ProtoReflect.Descriptor instead. func (*SendFilRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{28} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{30} } func (x *SendFilRequest) GetFrom() string { @@ -1529,7 +1614,7 @@ type SendFilResponse struct { func (x *SendFilResponse) Reset() { *x = SendFilResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[29] + mi := &file_powergate_user_v1_user_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1542,7 +1627,7 @@ func (x *SendFilResponse) String() string { func (*SendFilResponse) ProtoMessage() {} func (x *SendFilResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[29] + mi := &file_powergate_user_v1_user_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1555,7 +1640,7 @@ func (x *SendFilResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SendFilResponse.ProtoReflect.Descriptor instead. func (*SendFilResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{29} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{31} } type SignMessageRequest struct { @@ -1570,7 +1655,7 @@ type SignMessageRequest struct { func (x *SignMessageRequest) Reset() { *x = SignMessageRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[30] + mi := &file_powergate_user_v1_user_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1583,7 +1668,7 @@ func (x *SignMessageRequest) String() string { func (*SignMessageRequest) ProtoMessage() {} func (x *SignMessageRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[30] + mi := &file_powergate_user_v1_user_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1596,7 +1681,7 @@ func (x *SignMessageRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SignMessageRequest.ProtoReflect.Descriptor instead. func (*SignMessageRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{30} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{32} } func (x *SignMessageRequest) GetAddress() string { @@ -1624,7 +1709,7 @@ type SignMessageResponse struct { func (x *SignMessageResponse) Reset() { *x = SignMessageResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[31] + mi := &file_powergate_user_v1_user_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1637,7 +1722,7 @@ func (x *SignMessageResponse) String() string { func (*SignMessageResponse) ProtoMessage() {} func (x *SignMessageResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[31] + mi := &file_powergate_user_v1_user_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1650,7 +1735,7 @@ func (x *SignMessageResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SignMessageResponse.ProtoReflect.Descriptor instead. func (*SignMessageResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{31} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{33} } func (x *SignMessageResponse) GetSignature() []byte { @@ -1673,7 +1758,7 @@ type VerifyMessageRequest struct { func (x *VerifyMessageRequest) Reset() { *x = VerifyMessageRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[32] + mi := &file_powergate_user_v1_user_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1686,7 +1771,7 @@ func (x *VerifyMessageRequest) String() string { func (*VerifyMessageRequest) ProtoMessage() {} func (x *VerifyMessageRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[32] + mi := &file_powergate_user_v1_user_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1699,7 +1784,7 @@ func (x *VerifyMessageRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyMessageRequest.ProtoReflect.Descriptor instead. func (*VerifyMessageRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{32} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{34} } func (x *VerifyMessageRequest) GetAddress() string { @@ -1734,7 +1819,7 @@ type VerifyMessageResponse struct { func (x *VerifyMessageResponse) Reset() { *x = VerifyMessageResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[33] + mi := &file_powergate_user_v1_user_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1747,7 +1832,7 @@ func (x *VerifyMessageResponse) String() string { func (*VerifyMessageResponse) ProtoMessage() {} func (x *VerifyMessageResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[33] + mi := &file_powergate_user_v1_user_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1760,7 +1845,7 @@ func (x *VerifyMessageResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyMessageResponse.ProtoReflect.Descriptor instead. func (*VerifyMessageResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{33} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{35} } func (x *VerifyMessageResponse) GetOk() bool { @@ -1781,7 +1866,7 @@ type CancelStorageJobRequest struct { func (x *CancelStorageJobRequest) Reset() { *x = CancelStorageJobRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[34] + mi := &file_powergate_user_v1_user_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1794,7 +1879,7 @@ func (x *CancelStorageJobRequest) String() string { func (*CancelStorageJobRequest) ProtoMessage() {} func (x *CancelStorageJobRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[34] + mi := &file_powergate_user_v1_user_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1807,7 +1892,7 @@ func (x *CancelStorageJobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelStorageJobRequest.ProtoReflect.Descriptor instead. func (*CancelStorageJobRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{34} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{36} } func (x *CancelStorageJobRequest) GetJobId() string { @@ -1826,7 +1911,7 @@ type CancelStorageJobResponse struct { func (x *CancelStorageJobResponse) Reset() { *x = CancelStorageJobResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[35] + mi := &file_powergate_user_v1_user_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1839,7 +1924,7 @@ func (x *CancelStorageJobResponse) String() string { func (*CancelStorageJobResponse) ProtoMessage() {} func (x *CancelStorageJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[35] + mi := &file_powergate_user_v1_user_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1852,7 +1937,7 @@ func (x *CancelStorageJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelStorageJobResponse.ProtoReflect.Descriptor instead. func (*CancelStorageJobResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{35} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{37} } type StorageJobRequest struct { @@ -1866,7 +1951,7 @@ type StorageJobRequest struct { func (x *StorageJobRequest) Reset() { *x = StorageJobRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[36] + mi := &file_powergate_user_v1_user_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1879,7 +1964,7 @@ func (x *StorageJobRequest) String() string { func (*StorageJobRequest) ProtoMessage() {} func (x *StorageJobRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[36] + mi := &file_powergate_user_v1_user_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1892,7 +1977,7 @@ func (x *StorageJobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageJobRequest.ProtoReflect.Descriptor instead. func (*StorageJobRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{36} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{38} } func (x *StorageJobRequest) GetJobId() string { @@ -1913,7 +1998,7 @@ type StorageJobResponse struct { func (x *StorageJobResponse) Reset() { *x = StorageJobResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[37] + mi := &file_powergate_user_v1_user_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1926,7 +2011,7 @@ func (x *StorageJobResponse) String() string { func (*StorageJobResponse) ProtoMessage() {} func (x *StorageJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[37] + mi := &file_powergate_user_v1_user_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1939,7 +2024,7 @@ func (x *StorageJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageJobResponse.ProtoReflect.Descriptor instead. func (*StorageJobResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{37} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{39} } func (x *StorageJobResponse) GetStorageJob() *StorageJob { @@ -1960,7 +2045,7 @@ type StorageConfigForJobRequest struct { func (x *StorageConfigForJobRequest) Reset() { *x = StorageConfigForJobRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[38] + mi := &file_powergate_user_v1_user_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1973,7 +2058,7 @@ func (x *StorageConfigForJobRequest) String() string { func (*StorageConfigForJobRequest) ProtoMessage() {} func (x *StorageConfigForJobRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[38] + mi := &file_powergate_user_v1_user_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1986,7 +2071,7 @@ func (x *StorageConfigForJobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageConfigForJobRequest.ProtoReflect.Descriptor instead. func (*StorageConfigForJobRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{38} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{40} } func (x *StorageConfigForJobRequest) GetJobId() string { @@ -2007,7 +2092,7 @@ type StorageConfigForJobResponse struct { func (x *StorageConfigForJobResponse) Reset() { *x = StorageConfigForJobResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[39] + mi := &file_powergate_user_v1_user_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2020,7 +2105,7 @@ func (x *StorageConfigForJobResponse) String() string { func (*StorageConfigForJobResponse) ProtoMessage() {} func (x *StorageConfigForJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[39] + mi := &file_powergate_user_v1_user_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2033,7 +2118,7 @@ func (x *StorageConfigForJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageConfigForJobResponse.ProtoReflect.Descriptor instead. func (*StorageConfigForJobResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{39} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{41} } func (x *StorageConfigForJobResponse) GetStorageConfig() *StorageConfig { @@ -2054,7 +2139,7 @@ type QueuedStorageJobsRequest struct { func (x *QueuedStorageJobsRequest) Reset() { *x = QueuedStorageJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[40] + mi := &file_powergate_user_v1_user_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2067,7 +2152,7 @@ func (x *QueuedStorageJobsRequest) String() string { func (*QueuedStorageJobsRequest) ProtoMessage() {} func (x *QueuedStorageJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[40] + mi := &file_powergate_user_v1_user_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2080,7 +2165,7 @@ func (x *QueuedStorageJobsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use QueuedStorageJobsRequest.ProtoReflect.Descriptor instead. func (*QueuedStorageJobsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{40} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{42} } func (x *QueuedStorageJobsRequest) GetCids() []string { @@ -2101,7 +2186,7 @@ type QueuedStorageJobsResponse struct { func (x *QueuedStorageJobsResponse) Reset() { *x = QueuedStorageJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[41] + mi := &file_powergate_user_v1_user_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2114,7 +2199,7 @@ func (x *QueuedStorageJobsResponse) String() string { func (*QueuedStorageJobsResponse) ProtoMessage() {} func (x *QueuedStorageJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[41] + mi := &file_powergate_user_v1_user_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2127,7 +2212,7 @@ func (x *QueuedStorageJobsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use QueuedStorageJobsResponse.ProtoReflect.Descriptor instead. func (*QueuedStorageJobsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{41} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{43} } func (x *QueuedStorageJobsResponse) GetStorageJobs() []*StorageJob { @@ -2148,7 +2233,7 @@ type ExecutingStorageJobsRequest struct { func (x *ExecutingStorageJobsRequest) Reset() { *x = ExecutingStorageJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[42] + mi := &file_powergate_user_v1_user_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2161,7 +2246,7 @@ func (x *ExecutingStorageJobsRequest) String() string { func (*ExecutingStorageJobsRequest) ProtoMessage() {} func (x *ExecutingStorageJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[42] + mi := &file_powergate_user_v1_user_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2174,7 +2259,7 @@ func (x *ExecutingStorageJobsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutingStorageJobsRequest.ProtoReflect.Descriptor instead. func (*ExecutingStorageJobsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{42} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{44} } func (x *ExecutingStorageJobsRequest) GetCids() []string { @@ -2195,7 +2280,7 @@ type ExecutingStorageJobsResponse struct { func (x *ExecutingStorageJobsResponse) Reset() { *x = ExecutingStorageJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[43] + mi := &file_powergate_user_v1_user_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2208,7 +2293,7 @@ func (x *ExecutingStorageJobsResponse) String() string { func (*ExecutingStorageJobsResponse) ProtoMessage() {} func (x *ExecutingStorageJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[43] + mi := &file_powergate_user_v1_user_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2221,7 +2306,7 @@ func (x *ExecutingStorageJobsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutingStorageJobsResponse.ProtoReflect.Descriptor instead. func (*ExecutingStorageJobsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{43} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{45} } func (x *ExecutingStorageJobsResponse) GetStorageJobs() []*StorageJob { @@ -2242,7 +2327,7 @@ type LatestFinalStorageJobsRequest struct { func (x *LatestFinalStorageJobsRequest) Reset() { *x = LatestFinalStorageJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[44] + mi := &file_powergate_user_v1_user_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2255,7 +2340,7 @@ func (x *LatestFinalStorageJobsRequest) String() string { func (*LatestFinalStorageJobsRequest) ProtoMessage() {} func (x *LatestFinalStorageJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[44] + mi := &file_powergate_user_v1_user_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2268,7 +2353,7 @@ func (x *LatestFinalStorageJobsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LatestFinalStorageJobsRequest.ProtoReflect.Descriptor instead. func (*LatestFinalStorageJobsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{44} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{46} } func (x *LatestFinalStorageJobsRequest) GetCids() []string { @@ -2289,7 +2374,7 @@ type LatestFinalStorageJobsResponse struct { func (x *LatestFinalStorageJobsResponse) Reset() { *x = LatestFinalStorageJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[45] + mi := &file_powergate_user_v1_user_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2302,7 +2387,7 @@ func (x *LatestFinalStorageJobsResponse) String() string { func (*LatestFinalStorageJobsResponse) ProtoMessage() {} func (x *LatestFinalStorageJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[45] + mi := &file_powergate_user_v1_user_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2315,7 +2400,7 @@ func (x *LatestFinalStorageJobsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LatestFinalStorageJobsResponse.ProtoReflect.Descriptor instead. func (*LatestFinalStorageJobsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{45} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{47} } func (x *LatestFinalStorageJobsResponse) GetStorageJobs() []*StorageJob { @@ -2336,7 +2421,7 @@ type LatestSuccessfulStorageJobsRequest struct { func (x *LatestSuccessfulStorageJobsRequest) Reset() { *x = LatestSuccessfulStorageJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[46] + mi := &file_powergate_user_v1_user_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2349,7 +2434,7 @@ func (x *LatestSuccessfulStorageJobsRequest) String() string { func (*LatestSuccessfulStorageJobsRequest) ProtoMessage() {} func (x *LatestSuccessfulStorageJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[46] + mi := &file_powergate_user_v1_user_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2362,7 +2447,7 @@ func (x *LatestSuccessfulStorageJobsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use LatestSuccessfulStorageJobsRequest.ProtoReflect.Descriptor instead. func (*LatestSuccessfulStorageJobsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{46} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{48} } func (x *LatestSuccessfulStorageJobsRequest) GetCids() []string { @@ -2383,7 +2468,7 @@ type LatestSuccessfulStorageJobsResponse struct { func (x *LatestSuccessfulStorageJobsResponse) Reset() { *x = LatestSuccessfulStorageJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[47] + mi := &file_powergate_user_v1_user_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2396,7 +2481,7 @@ func (x *LatestSuccessfulStorageJobsResponse) String() string { func (*LatestSuccessfulStorageJobsResponse) ProtoMessage() {} func (x *LatestSuccessfulStorageJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[47] + mi := &file_powergate_user_v1_user_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2409,7 +2494,7 @@ func (x *LatestSuccessfulStorageJobsResponse) ProtoReflect() protoreflect.Messag // Deprecated: Use LatestSuccessfulStorageJobsResponse.ProtoReflect.Descriptor instead. func (*LatestSuccessfulStorageJobsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{47} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{49} } func (x *LatestSuccessfulStorageJobsResponse) GetStorageJobs() []*StorageJob { @@ -2430,7 +2515,7 @@ type StorageJobsSummaryRequest struct { func (x *StorageJobsSummaryRequest) Reset() { *x = StorageJobsSummaryRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[48] + mi := &file_powergate_user_v1_user_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2443,7 +2528,7 @@ func (x *StorageJobsSummaryRequest) String() string { func (*StorageJobsSummaryRequest) ProtoMessage() {} func (x *StorageJobsSummaryRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[48] + mi := &file_powergate_user_v1_user_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2456,7 +2541,7 @@ func (x *StorageJobsSummaryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageJobsSummaryRequest.ProtoReflect.Descriptor instead. func (*StorageJobsSummaryRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{48} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{50} } func (x *StorageJobsSummaryRequest) GetCids() []string { @@ -2481,7 +2566,7 @@ type StorageJobsSummaryResponse struct { func (x *StorageJobsSummaryResponse) Reset() { *x = StorageJobsSummaryResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[49] + mi := &file_powergate_user_v1_user_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2494,7 +2579,7 @@ func (x *StorageJobsSummaryResponse) String() string { func (*StorageJobsSummaryResponse) ProtoMessage() {} func (x *StorageJobsSummaryResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[49] + mi := &file_powergate_user_v1_user_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2507,7 +2592,7 @@ func (x *StorageJobsSummaryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageJobsSummaryResponse.ProtoReflect.Descriptor instead. func (*StorageJobsSummaryResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{49} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{51} } func (x *StorageJobsSummaryResponse) GetJobCounts() *JobCounts { @@ -2556,7 +2641,7 @@ type WatchStorageJobsRequest struct { func (x *WatchStorageJobsRequest) Reset() { *x = WatchStorageJobsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[50] + mi := &file_powergate_user_v1_user_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2569,7 +2654,7 @@ func (x *WatchStorageJobsRequest) String() string { func (*WatchStorageJobsRequest) ProtoMessage() {} func (x *WatchStorageJobsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[50] + mi := &file_powergate_user_v1_user_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2582,7 +2667,7 @@ func (x *WatchStorageJobsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchStorageJobsRequest.ProtoReflect.Descriptor instead. func (*WatchStorageJobsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{50} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{52} } func (x *WatchStorageJobsRequest) GetJobIds() []string { @@ -2603,7 +2688,7 @@ type WatchStorageJobsResponse struct { func (x *WatchStorageJobsResponse) Reset() { *x = WatchStorageJobsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[51] + mi := &file_powergate_user_v1_user_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2616,7 +2701,7 @@ func (x *WatchStorageJobsResponse) String() string { func (*WatchStorageJobsResponse) ProtoMessage() {} func (x *WatchStorageJobsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[51] + mi := &file_powergate_user_v1_user_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2629,7 +2714,7 @@ func (x *WatchStorageJobsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchStorageJobsResponse.ProtoReflect.Descriptor instead. func (*WatchStorageJobsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{51} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{53} } func (x *WatchStorageJobsResponse) GetStorageJob() *StorageJob { @@ -2650,7 +2735,7 @@ type StorageDealRecordsRequest struct { func (x *StorageDealRecordsRequest) Reset() { *x = StorageDealRecordsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[52] + mi := &file_powergate_user_v1_user_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2663,7 +2748,7 @@ func (x *StorageDealRecordsRequest) String() string { func (*StorageDealRecordsRequest) ProtoMessage() {} func (x *StorageDealRecordsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[52] + mi := &file_powergate_user_v1_user_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2676,7 +2761,7 @@ func (x *StorageDealRecordsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageDealRecordsRequest.ProtoReflect.Descriptor instead. func (*StorageDealRecordsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{52} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{54} } func (x *StorageDealRecordsRequest) GetConfig() *DealRecordsConfig { @@ -2697,7 +2782,7 @@ type StorageDealRecordsResponse struct { func (x *StorageDealRecordsResponse) Reset() { *x = StorageDealRecordsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[53] + mi := &file_powergate_user_v1_user_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2710,7 +2795,7 @@ func (x *StorageDealRecordsResponse) String() string { func (*StorageDealRecordsResponse) ProtoMessage() {} func (x *StorageDealRecordsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[53] + mi := &file_powergate_user_v1_user_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2723,7 +2808,7 @@ func (x *StorageDealRecordsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageDealRecordsResponse.ProtoReflect.Descriptor instead. func (*StorageDealRecordsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{53} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{55} } func (x *StorageDealRecordsResponse) GetRecords() []*StorageDealRecord { @@ -2744,7 +2829,7 @@ type RetrievalDealRecordsRequest struct { func (x *RetrievalDealRecordsRequest) Reset() { *x = RetrievalDealRecordsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[54] + mi := &file_powergate_user_v1_user_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2757,7 +2842,7 @@ func (x *RetrievalDealRecordsRequest) String() string { func (*RetrievalDealRecordsRequest) ProtoMessage() {} func (x *RetrievalDealRecordsRequest) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[54] + mi := &file_powergate_user_v1_user_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2770,7 +2855,7 @@ func (x *RetrievalDealRecordsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RetrievalDealRecordsRequest.ProtoReflect.Descriptor instead. func (*RetrievalDealRecordsRequest) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{54} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{56} } func (x *RetrievalDealRecordsRequest) GetConfig() *DealRecordsConfig { @@ -2791,7 +2876,7 @@ type RetrievalDealRecordsResponse struct { func (x *RetrievalDealRecordsResponse) Reset() { *x = RetrievalDealRecordsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[55] + mi := &file_powergate_user_v1_user_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2804,7 +2889,7 @@ func (x *RetrievalDealRecordsResponse) String() string { func (*RetrievalDealRecordsResponse) ProtoMessage() {} func (x *RetrievalDealRecordsResponse) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[55] + mi := &file_powergate_user_v1_user_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2817,7 +2902,7 @@ func (x *RetrievalDealRecordsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RetrievalDealRecordsResponse.ProtoReflect.Descriptor instead. func (*RetrievalDealRecordsResponse) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{55} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{57} } func (x *RetrievalDealRecordsResponse) GetRecords() []*RetrievalDealRecord { @@ -2841,7 +2926,7 @@ type JobCounts struct { func (x *JobCounts) Reset() { *x = JobCounts{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[56] + mi := &file_powergate_user_v1_user_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2854,7 +2939,7 @@ func (x *JobCounts) String() string { func (*JobCounts) ProtoMessage() {} func (x *JobCounts) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[56] + mi := &file_powergate_user_v1_user_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2867,7 +2952,7 @@ func (x *JobCounts) ProtoReflect() protoreflect.Message { // Deprecated: Use JobCounts.ProtoReflect.Descriptor instead. func (*JobCounts) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{56} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{58} } func (x *JobCounts) GetQueued() int32 { @@ -2912,7 +2997,7 @@ type AddrInfo struct { func (x *AddrInfo) Reset() { *x = AddrInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[57] + mi := &file_powergate_user_v1_user_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2925,7 +3010,7 @@ func (x *AddrInfo) String() string { func (*AddrInfo) ProtoMessage() {} func (x *AddrInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[57] + mi := &file_powergate_user_v1_user_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2938,7 +3023,7 @@ func (x *AddrInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use AddrInfo.ProtoReflect.Descriptor instead. func (*AddrInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{57} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{59} } func (x *AddrInfo) GetName() string { @@ -2980,7 +3065,7 @@ type IpfsConfig struct { func (x *IpfsConfig) Reset() { *x = IpfsConfig{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[58] + mi := &file_powergate_user_v1_user_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2993,7 +3078,7 @@ func (x *IpfsConfig) String() string { func (*IpfsConfig) ProtoMessage() {} func (x *IpfsConfig) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[58] + mi := &file_powergate_user_v1_user_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3006,7 +3091,7 @@ func (x *IpfsConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use IpfsConfig.ProtoReflect.Descriptor instead. func (*IpfsConfig) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{58} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{60} } func (x *IpfsConfig) GetAddTimeout() int64 { @@ -3030,7 +3115,7 @@ type HotConfig struct { func (x *HotConfig) Reset() { *x = HotConfig{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[59] + mi := &file_powergate_user_v1_user_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3043,7 +3128,7 @@ func (x *HotConfig) String() string { func (*HotConfig) ProtoMessage() {} func (x *HotConfig) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[59] + mi := &file_powergate_user_v1_user_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3056,7 +3141,7 @@ func (x *HotConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use HotConfig.ProtoReflect.Descriptor instead. func (*HotConfig) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{59} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{61} } func (x *HotConfig) GetEnabled() bool { @@ -3099,7 +3184,7 @@ type FilRenew struct { func (x *FilRenew) Reset() { *x = FilRenew{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[60] + mi := &file_powergate_user_v1_user_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3112,7 +3197,7 @@ func (x *FilRenew) String() string { func (*FilRenew) ProtoMessage() {} func (x *FilRenew) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[60] + mi := &file_powergate_user_v1_user_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3125,7 +3210,7 @@ func (x *FilRenew) ProtoReflect() protoreflect.Message { // Deprecated: Use FilRenew.ProtoReflect.Descriptor instead. func (*FilRenew) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{60} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{62} } func (x *FilRenew) GetEnabled() bool { @@ -3162,7 +3247,7 @@ type FilConfig struct { func (x *FilConfig) Reset() { *x = FilConfig{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[61] + mi := &file_powergate_user_v1_user_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3175,7 +3260,7 @@ func (x *FilConfig) String() string { func (*FilConfig) ProtoMessage() {} func (x *FilConfig) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[61] + mi := &file_powergate_user_v1_user_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3188,7 +3273,7 @@ func (x *FilConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use FilConfig.ProtoReflect.Descriptor instead. func (*FilConfig) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{61} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{63} } func (x *FilConfig) GetReplicationFactor() int64 { @@ -3273,7 +3358,7 @@ type ColdConfig struct { func (x *ColdConfig) Reset() { *x = ColdConfig{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[62] + mi := &file_powergate_user_v1_user_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3286,7 +3371,7 @@ func (x *ColdConfig) String() string { func (*ColdConfig) ProtoMessage() {} func (x *ColdConfig) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[62] + mi := &file_powergate_user_v1_user_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3299,7 +3384,7 @@ func (x *ColdConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use ColdConfig.ProtoReflect.Descriptor instead. func (*ColdConfig) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{62} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{64} } func (x *ColdConfig) GetEnabled() bool { @@ -3329,7 +3414,7 @@ type StorageConfig struct { func (x *StorageConfig) Reset() { *x = StorageConfig{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[63] + mi := &file_powergate_user_v1_user_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3342,7 +3427,7 @@ func (x *StorageConfig) String() string { func (*StorageConfig) ProtoMessage() {} func (x *StorageConfig) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[63] + mi := &file_powergate_user_v1_user_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3355,7 +3440,7 @@ func (x *StorageConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageConfig.ProtoReflect.Descriptor instead. func (*StorageConfig) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{63} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{65} } func (x *StorageConfig) GetHot() *HotConfig { @@ -3390,7 +3475,7 @@ type IpfsHotInfo struct { func (x *IpfsHotInfo) Reset() { *x = IpfsHotInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[64] + mi := &file_powergate_user_v1_user_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3403,7 +3488,7 @@ func (x *IpfsHotInfo) String() string { func (*IpfsHotInfo) ProtoMessage() {} func (x *IpfsHotInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[64] + mi := &file_powergate_user_v1_user_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3416,7 +3501,7 @@ func (x *IpfsHotInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use IpfsHotInfo.ProtoReflect.Descriptor instead. func (*IpfsHotInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{64} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{66} } func (x *IpfsHotInfo) GetCreated() int64 { @@ -3439,7 +3524,7 @@ type HotInfo struct { func (x *HotInfo) Reset() { *x = HotInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[65] + mi := &file_powergate_user_v1_user_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3452,7 +3537,7 @@ func (x *HotInfo) String() string { func (*HotInfo) ProtoMessage() {} func (x *HotInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[65] + mi := &file_powergate_user_v1_user_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3465,7 +3550,7 @@ func (x *HotInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use HotInfo.ProtoReflect.Descriptor instead. func (*HotInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{65} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{67} } func (x *HotInfo) GetEnabled() bool { @@ -3507,7 +3592,7 @@ type FilStorage struct { func (x *FilStorage) Reset() { *x = FilStorage{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[66] + mi := &file_powergate_user_v1_user_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3520,7 +3605,7 @@ func (x *FilStorage) String() string { func (*FilStorage) ProtoMessage() {} func (x *FilStorage) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[66] + mi := &file_powergate_user_v1_user_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3533,7 +3618,7 @@ func (x *FilStorage) ProtoReflect() protoreflect.Message { // Deprecated: Use FilStorage.ProtoReflect.Descriptor instead. func (*FilStorage) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{66} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{68} } func (x *FilStorage) GetProposalCid() string { @@ -3605,7 +3690,7 @@ type FilInfo struct { func (x *FilInfo) Reset() { *x = FilInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[67] + mi := &file_powergate_user_v1_user_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3618,7 +3703,7 @@ func (x *FilInfo) String() string { func (*FilInfo) ProtoMessage() {} func (x *FilInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[67] + mi := &file_powergate_user_v1_user_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3631,7 +3716,7 @@ func (x *FilInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use FilInfo.ProtoReflect.Descriptor instead. func (*FilInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{67} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{69} } func (x *FilInfo) GetDataCid() string { @@ -3667,7 +3752,7 @@ type ColdInfo struct { func (x *ColdInfo) Reset() { *x = ColdInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[68] + mi := &file_powergate_user_v1_user_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3680,7 +3765,7 @@ func (x *ColdInfo) String() string { func (*ColdInfo) ProtoMessage() {} func (x *ColdInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[68] + mi := &file_powergate_user_v1_user_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3693,7 +3778,7 @@ func (x *ColdInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ColdInfo.ProtoReflect.Descriptor instead. func (*ColdInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{68} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{70} } func (x *ColdInfo) GetEnabled() bool { @@ -3725,7 +3810,7 @@ type StorageInfo struct { func (x *StorageInfo) Reset() { *x = StorageInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[69] + mi := &file_powergate_user_v1_user_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3738,7 +3823,7 @@ func (x *StorageInfo) String() string { func (*StorageInfo) ProtoMessage() {} func (x *StorageInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[69] + mi := &file_powergate_user_v1_user_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3751,7 +3836,7 @@ func (x *StorageInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageInfo.ProtoReflect.Descriptor instead. func (*StorageInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{69} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{71} } func (x *StorageInfo) GetJobId() string { @@ -3806,7 +3891,7 @@ type CidInfo struct { func (x *CidInfo) Reset() { *x = CidInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[70] + mi := &file_powergate_user_v1_user_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3819,7 +3904,7 @@ func (x *CidInfo) String() string { func (*CidInfo) ProtoMessage() {} func (x *CidInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[70] + mi := &file_powergate_user_v1_user_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3832,7 +3917,7 @@ func (x *CidInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use CidInfo.ProtoReflect.Descriptor instead. func (*CidInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{70} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{72} } func (x *CidInfo) GetCid() string { @@ -3906,7 +3991,7 @@ type DealInfo struct { func (x *DealInfo) Reset() { *x = DealInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[71] + mi := &file_powergate_user_v1_user_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3919,7 +4004,7 @@ func (x *DealInfo) String() string { func (*DealInfo) ProtoMessage() {} func (x *DealInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[71] + mi := &file_powergate_user_v1_user_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3932,7 +4017,7 @@ func (x *DealInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use DealInfo.ProtoReflect.Descriptor instead. func (*DealInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{71} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{73} } func (x *DealInfo) GetProposalCid() string { @@ -4037,7 +4122,7 @@ type StorageJob struct { func (x *StorageJob) Reset() { *x = StorageJob{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[72] + mi := &file_powergate_user_v1_user_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4050,7 +4135,7 @@ func (x *StorageJob) String() string { func (*StorageJob) ProtoMessage() {} func (x *StorageJob) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[72] + mi := &file_powergate_user_v1_user_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4063,7 +4148,7 @@ func (x *StorageJob) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageJob.ProtoReflect.Descriptor instead. func (*StorageJob) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{72} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{74} } func (x *StorageJob) GetId() string { @@ -4135,7 +4220,7 @@ type DealError struct { func (x *DealError) Reset() { *x = DealError{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[73] + mi := &file_powergate_user_v1_user_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4148,7 +4233,7 @@ func (x *DealError) String() string { func (*DealError) ProtoMessage() {} func (x *DealError) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[73] + mi := &file_powergate_user_v1_user_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4161,7 +4246,7 @@ func (x *DealError) ProtoReflect() protoreflect.Message { // Deprecated: Use DealError.ProtoReflect.Descriptor instead. func (*DealError) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{73} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{75} } func (x *DealError) GetProposalCid() string { @@ -4199,7 +4284,7 @@ type LogEntry struct { func (x *LogEntry) Reset() { *x = LogEntry{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[74] + mi := &file_powergate_user_v1_user_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4212,7 +4297,7 @@ func (x *LogEntry) String() string { func (*LogEntry) ProtoMessage() {} func (x *LogEntry) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[74] + mi := &file_powergate_user_v1_user_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4225,7 +4310,7 @@ func (x *LogEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use LogEntry.ProtoReflect.Descriptor instead. func (*LogEntry) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{74} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{76} } func (x *LogEntry) GetCid() string { @@ -4271,7 +4356,7 @@ type DealRecordsConfig struct { func (x *DealRecordsConfig) Reset() { *x = DealRecordsConfig{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[75] + mi := &file_powergate_user_v1_user_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4284,7 +4369,7 @@ func (x *DealRecordsConfig) String() string { func (*DealRecordsConfig) ProtoMessage() {} func (x *DealRecordsConfig) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[75] + mi := &file_powergate_user_v1_user_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4297,7 +4382,7 @@ func (x *DealRecordsConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use DealRecordsConfig.ProtoReflect.Descriptor instead. func (*DealRecordsConfig) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{75} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{77} } func (x *DealRecordsConfig) GetFromAddrs() []string { @@ -4357,7 +4442,7 @@ type StorageDealInfo struct { func (x *StorageDealInfo) Reset() { *x = StorageDealInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[76] + mi := &file_powergate_user_v1_user_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4370,7 +4455,7 @@ func (x *StorageDealInfo) String() string { func (*StorageDealInfo) ProtoMessage() {} func (x *StorageDealInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[76] + mi := &file_powergate_user_v1_user_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4383,7 +4468,7 @@ func (x *StorageDealInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageDealInfo.ProtoReflect.Descriptor instead. func (*StorageDealInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{76} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{78} } func (x *StorageDealInfo) GetProposalCid() string { @@ -4485,7 +4570,7 @@ type StorageDealRecord struct { func (x *StorageDealRecord) Reset() { *x = StorageDealRecord{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[77] + mi := &file_powergate_user_v1_user_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4498,7 +4583,7 @@ func (x *StorageDealRecord) String() string { func (*StorageDealRecord) ProtoMessage() {} func (x *StorageDealRecord) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[77] + mi := &file_powergate_user_v1_user_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4511,7 +4596,7 @@ func (x *StorageDealRecord) ProtoReflect() protoreflect.Message { // Deprecated: Use StorageDealRecord.ProtoReflect.Descriptor instead. func (*StorageDealRecord) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{77} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{79} } func (x *StorageDealRecord) GetRootCid() string { @@ -4566,7 +4651,7 @@ type RetrievalDealInfo struct { func (x *RetrievalDealInfo) Reset() { *x = RetrievalDealInfo{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[78] + mi := &file_powergate_user_v1_user_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4579,7 +4664,7 @@ func (x *RetrievalDealInfo) String() string { func (*RetrievalDealInfo) ProtoMessage() {} func (x *RetrievalDealInfo) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[78] + mi := &file_powergate_user_v1_user_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4592,7 +4677,7 @@ func (x *RetrievalDealInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use RetrievalDealInfo.ProtoReflect.Descriptor instead. func (*RetrievalDealInfo) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{78} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{80} } func (x *RetrievalDealInfo) GetRootCid() string { @@ -4657,7 +4742,7 @@ type RetrievalDealRecord struct { func (x *RetrievalDealRecord) Reset() { *x = RetrievalDealRecord{} if protoimpl.UnsafeEnabled { - mi := &file_powergate_user_v1_user_proto_msgTypes[79] + mi := &file_powergate_user_v1_user_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4670,7 +4755,7 @@ func (x *RetrievalDealRecord) String() string { func (*RetrievalDealRecord) ProtoMessage() {} func (x *RetrievalDealRecord) ProtoReflect() protoreflect.Message { - mi := &file_powergate_user_v1_user_proto_msgTypes[79] + mi := &file_powergate_user_v1_user_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4683,7 +4768,7 @@ func (x *RetrievalDealRecord) ProtoReflect() protoreflect.Message { // Deprecated: Use RetrievalDealRecord.ProtoReflect.Descriptor instead. func (*RetrievalDealRecord) Descriptor() ([]byte, []int) { - return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{79} + return file_powergate_user_v1_user_proto_rawDescGZIP(), []int{81} } func (x *RetrievalDealRecord) GetAddress() string { @@ -4753,569 +4838,578 @@ var file_powergate_user_v1_user_proto_rawDesc = []byte{ 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x21, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, - 0x69, 0x64, 0x22, 0xdf, 0x01, 0x0a, 0x19, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, - 0x69, 0x64, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, - 0x68, 0x61, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x6f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x13, 0x68, 0x61, 0x73, 0x5f, 0x6f, 0x76, 0x65, 0x72, - 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x11, 0x68, 0x61, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x22, 0x33, 0x0a, 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x70, - 0x6c, 0x61, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, - 0x69, 0x64, 0x31, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x32, 0x22, 0x2c, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6c, 0x61, - 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, - 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x1e, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0x23, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x21, 0x0a, 0x0d, 0x52, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0x10, 0x0a, - 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x55, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, - 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x4d, 0x0a, 0x11, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, - 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x6c, - 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6c, 0x6f, 0x67, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x24, 0x0a, 0x0e, 0x43, 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x4a, 0x0a, 0x0f, 0x43, - 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, - 0x0a, 0x09, 0x63, 0x69, 0x64, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, - 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x22, 0x2a, 0x0a, 0x0e, 0x42, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x22, 0x2b, 0x0a, 0x0f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x22, 0x6d, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, - 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0b, 0x6d, 0x61, 0x6b, 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, - 0x2e, 0x0a, 0x12, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, - 0x12, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x4e, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, - 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x64, 0x64, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x22, 0x4c, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x33, - 0x0a, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x22, 0x68, 0x0a, 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x27, 0x0a, - 0x15, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x22, 0x30, 0x0a, 0x17, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, - 0x22, 0x54, 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, + 0x69, 0x64, 0x22, 0x23, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x67, 0x65, 0x43, 0x69, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x67, 0x65, + 0x43, 0x69, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xdf, 0x01, 0x0a, 0x19, + 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x22, 0x33, 0x0a, 0x1a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x1b, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x4a, - 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0e, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x22, 0x2e, 0x0a, 0x18, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, - 0x69, 0x64, 0x73, 0x22, 0x5d, 0x0a, 0x19, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x22, 0x31, 0x0a, 0x1b, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x60, 0x0a, 0x1c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x61, 0x73, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x61, 0x73, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, + 0x13, 0x68, 0x61, 0x73, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x73, 0x4f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x33, 0x0a, + 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6a, + 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, + 0x49, 0x64, 0x22, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x31, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x31, 0x12, 0x12, 0x0a, 0x04, + 0x63, 0x69, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x32, + 0x22, 0x2c, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x1e, + 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0x23, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, + 0x75, 0x6e, 0x6b, 0x22, 0x21, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x15, + 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x22, + 0x4d, 0x0a, 0x11, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x24, + 0x0a, 0x0e, 0x43, 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x69, 0x64, 0x73, 0x22, 0x4a, 0x0a, 0x0f, 0x43, 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x63, 0x69, 0x64, 0x5f, 0x69, + 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x73, + 0x22, 0x2a, 0x0a, 0x0e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2b, 0x0a, 0x0f, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x6d, 0x0a, 0x11, 0x4e, 0x65, 0x77, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6d, 0x61, 0x6b, + 0x65, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x4e, 0x65, 0x77, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x12, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4e, 0x0a, 0x11, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x39, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4c, 0x0a, 0x0e, + 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x74, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x65, + 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, + 0x12, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x68, 0x0a, 0x14, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x27, 0x0a, 0x15, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x22, + 0x30, 0x0a, 0x17, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, + 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, + 0x64, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x0a, + 0x11, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x22, 0x54, 0x0a, 0x12, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3e, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x22, + 0x33, 0x0a, 0x1a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x46, 0x6f, 0x72, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, + 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, + 0x6f, 0x62, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x1b, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x33, 0x0a, 0x1d, 0x4c, 0x61, 0x74, 0x65, 0x73, - 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2e, 0x0a, 0x18, + 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x62, 0x0a, 0x1e, - 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x5d, 0x0a, 0x19, + 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0b, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x31, 0x0a, 0x1b, 0x45, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, + 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x60, + 0x0a, 0x1c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, - 0x22, 0x38, 0x0a, 0x22, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x67, 0x0a, 0x23, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x73, 0x22, 0x2f, 0x0a, 0x19, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, - 0x63, 0x69, 0x64, 0x73, 0x22, 0xbb, 0x03, 0x0a, 0x1a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x6a, 0x6f, 0x62, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, - 0x12, 0x4d, 0x0a, 0x13, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x22, 0x33, 0x0a, 0x1d, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0x62, 0x0a, 0x1e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, + 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x11, 0x71, 0x75, - 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, - 0x53, 0x0a, 0x16, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x14, - 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x58, 0x0a, 0x19, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x66, - 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x16, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x62, - 0x0a, 0x1e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x66, 0x75, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x1b, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, + 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0b, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x38, 0x0a, 0x22, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, + 0x69, 0x64, 0x73, 0x22, 0x67, 0x0a, 0x23, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x22, 0x32, 0x0a, 0x17, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, - 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x73, 0x22, 0x5a, 0x0a, 0x18, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, - 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x22, 0x59, 0x0a, 0x19, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, - 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x3c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x5c, 0x0a, - 0x1a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x72, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, - 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x5b, 0x0a, 0x1b, 0x52, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x77, - 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x60, 0x0a, 0x1c, 0x52, 0x65, 0x74, 0x72, - 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x77, 0x65, - 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x09, 0x4a, - 0x6f, 0x62, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x71, 0x75, 0x65, 0x75, - 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x21, - 0x0a, 0x0c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, - 0x6c, 0x12, 0x2b, 0x0a, 0x11, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x66, - 0x0a, 0x08, 0x41, 0x64, 0x64, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x2d, 0x0a, 0x0a, 0x49, 0x70, 0x66, 0x73, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xad, 0x01, 0x0a, 0x09, 0x48, 0x6f, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x25, 0x0a, - 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x6e, 0x66, 0x72, - 0x65, 0x65, 0x7a, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, - 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x10, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4d, 0x61, 0x78, 0x50, 0x72, 0x69, - 0x63, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x69, 0x70, 0x66, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x70, 0x66, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x04, 0x69, 0x70, 0x66, 0x73, 0x22, 0x42, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x6e, 0x65, - 0x77, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x98, 0x03, 0x0a, 0x09, 0x46, 0x69, - 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x6d, - 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0f, 0x64, 0x65, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x6d, - 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x78, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, - 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x6e, 0x65, - 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, - 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x65, 0x6e, 0x65, 0x77, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x52, 0x65, - 0x6e, 0x65, 0x77, 0x52, 0x05, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x69, 0x63, - 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, - 0x76, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x66, 0x61, 0x73, 0x74, 0x52, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x61, 0x6c, - 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x22, 0x60, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x08, - 0x66, 0x69, 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x66, 0x69, - 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x22, 0x92, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x12, 0x31, 0x0a, 0x04, 0x63, 0x6f, 0x6c, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x64, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, 0x63, 0x6f, 0x6c, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x72, - 0x65, 0x70, 0x61, 0x69, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x72, 0x65, 0x70, 0x61, 0x69, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x27, 0x0a, 0x0b, 0x49, - 0x70, 0x66, 0x73, 0x48, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x22, 0x6b, 0x0a, 0x07, 0x48, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x32, 0x0a, - 0x04, 0x69, 0x70, 0x66, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x6f, - 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x70, 0x66, 0x73, 0x48, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x70, 0x66, - 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0a, 0x46, 0x69, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, - 0x43, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x65, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x65, 0x64, 0x12, 0x1a, 0x0a, - 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, - 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x70, - 0x6f, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x65, - 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0a, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, - 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x69, 0x65, 0x63, 0x65, 0x43, 0x69, 0x64, 0x22, 0x75, 0x0a, 0x07, 0x46, 0x69, 0x6c, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x61, 0x74, 0x61, 0x43, 0x69, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, - 0x69, 0x7a, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x53, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x73, - 0x22, 0x5c, 0x0a, 0x08, 0x43, 0x6f, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, + 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x2f, 0x0a, 0x19, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x73, 0x22, 0xbb, 0x03, + 0x0a, 0x1a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0a, + 0x6a, 0x6f, 0x62, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x09, + 0x6a, 0x6f, 0x62, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x4d, 0x0a, 0x13, 0x71, 0x75, 0x65, + 0x75, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x11, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x53, 0x0a, 0x16, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, + 0x62, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x14, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x58, 0x0a, + 0x19, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, + 0x16, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x62, 0x0a, 0x1e, 0x6c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x5f, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x1b, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x32, 0x0a, 0x17, 0x57, + 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x73, 0x22, + 0x5a, 0x0a, 0x18, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, + 0x6f, 0x62, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, + 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x22, 0x59, 0x0a, 0x19, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x61, + 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x5c, 0x0a, 0x1a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x73, 0x22, 0x5b, 0x0a, 0x1b, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, + 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x22, 0x60, 0x0a, 0x1c, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, + 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x40, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, + 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x11, 0x6c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x66, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, + 0x2d, 0x0a, 0x0a, 0x49, 0x70, 0x66, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, + 0x0b, 0x61, 0x64, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xad, + 0x01, 0x0a, 0x09, 0x48, 0x6f, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x63, 0x6f, - 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, - 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x22, 0xaf, - 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, - 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x12, 0x2c, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, + 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x12, 0x2c, 0x0a, + 0x12, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x75, 0x6e, 0x66, 0x72, 0x65, + 0x65, 0x7a, 0x65, 0x4d, 0x61, 0x78, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x69, + 0x70, 0x66, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, + 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x70, + 0x66, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, 0x69, 0x70, 0x66, 0x73, 0x22, 0x42, + 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x6e, 0x65, 0x77, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, + 0x6c, 0x64, 0x22, 0x98, 0x03, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x72, 0x65, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x61, 0x6c, + 0x4d, 0x69, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x65, + 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x69, + 0x6e, 0x65, 0x72, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, + 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, + 0x12, 0x31, 0x0a, 0x05, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x6e, 0x65, 0x77, 0x52, 0x05, 0x72, 0x65, + 0x6e, 0x65, 0x77, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x61, + 0x73, 0x74, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0d, 0x66, 0x61, 0x73, 0x74, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, + 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x64, 0x65, + 0x61, 0x6c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x60, 0x0a, + 0x0a, 0x43, 0x6f, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x63, 0x6f, 0x69, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x22, + 0x92, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x2e, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x12, - 0x2f, 0x0a, 0x04, 0x63, 0x6f, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x68, 0x6f, + 0x74, 0x12, 0x31, 0x0a, 0x04, 0x63, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x04, + 0x63, 0x6f, 0x6c, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x61, 0x69, 0x72, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x61, 0x69, 0x72, + 0x61, 0x62, 0x6c, 0x65, 0x22, 0x27, 0x0a, 0x0b, 0x49, 0x70, 0x66, 0x73, 0x48, 0x6f, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x6b, 0x0a, + 0x07, 0x48, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x69, 0x70, 0x66, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x70, 0x66, 0x73, 0x48, 0x6f, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x70, 0x66, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0a, 0x46, + 0x69, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, + 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x43, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x72, 0x65, 0x6e, 0x65, 0x77, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, + 0x65, 0x6e, 0x65, 0x77, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1f, 0x0a, + 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x14, + 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, + 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, + 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x69, 0x65, 0x63, 0x65, 0x43, + 0x69, 0x64, 0x22, 0x75, 0x0a, 0x07, 0x46, 0x69, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, + 0x08, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x64, 0x61, 0x74, 0x61, 0x43, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x3b, 0x0a, 0x09, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x09, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x73, 0x22, 0x5c, 0x0a, 0x08, 0x43, 0x6f, 0x6c, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, + 0x36, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x66, + 0x69, 0x6c, 0x65, 0x63, 0x6f, 0x69, 0x6e, 0x22, 0xaf, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x10, + 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x03, 0x68, 0x6f, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x63, 0x6f, 0x6c, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x64, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x63, 0x6f, 0x6c, 0x64, 0x22, 0xac, 0x04, 0x0a, 0x07, 0x43, 0x69, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x61, 0x0a, 0x1c, 0x6c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x63, 0x6f, 0x6c, 0x64, - 0x22, 0xac, 0x04, 0x0a, 0x07, 0x43, 0x69, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, - 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x61, - 0x0a, 0x1c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x65, 0x64, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x19, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x50, 0x75, - 0x73, 0x68, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x50, 0x0a, 0x14, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x4d, 0x0a, 0x13, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x5f, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, + 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x19, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x50, 0x75, 0x73, 0x68, 0x65, 0x64, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x50, 0x0a, 0x14, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4d, 0x0a, 0x13, + 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, + 0x6f, 0x62, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, + 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x11, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x51, 0x0a, 0x15, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x56, + 0x0a, 0x18, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, - 0x11, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, - 0x62, 0x73, 0x12, 0x51, 0x0a, 0x15, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, - 0x52, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x56, 0x0a, 0x18, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, - 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, - 0x62, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x15, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x60, 0x0a, - 0x1d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, - 0x75, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x4a, 0x6f, 0x62, 0x52, 0x1a, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x22, - 0xf1, 0x02, 0x0a, 0x08, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x0c, - 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x43, 0x69, 0x64, 0x12, - 0x19, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x07, 0x73, 0x74, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, - 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x70, 0x69, 0x65, 0x63, 0x65, 0x43, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, - 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x65, 0x70, - 0x6f, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, - 0x50, 0x65, 0x72, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x64, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x29, - 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x70, 0x6f, - 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0xb4, 0x02, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, - 0x6f, 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x69, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x69, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x6f, - 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x61, 0x75, - 0x73, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x08, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x0b, - 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, - 0x0a, 0x64, 0x65, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x5e, 0x0a, 0x09, 0x44, 0x65, - 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x6f, - 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, - 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x43, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, - 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61, 0x0a, 0x08, 0x4c, 0x6f, - 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, - 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbb, 0x01, - 0x0a, 0x11, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, - 0x72, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x43, 0x69, 0x64, 0x73, 0x12, - 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x1c, 0x0a, - 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xf8, 0x02, 0x0a, 0x0f, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x43, - 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x73, 0x74, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, - 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x69, 0x65, 0x63, 0x65, 0x43, 0x69, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, - 0x69, 0x7a, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, - 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x72, - 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, - 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x61, 0x6c, - 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x64, 0x65, 0x61, 0x6c, 0x49, - 0x64, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x19, 0x0a, 0x08, - 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, - 0x3f, 0x0a, 0x09, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, - 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, - 0x22, 0x80, 0x02, 0x0a, 0x11, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, - 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x69, - 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x69, - 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3a, 0x0a, - 0x19, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x5f, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x17, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, - 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, - 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x86, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, - 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x64, 0x65, 0x61, - 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, - 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x08, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x2a, 0xa0, 0x01, 0x0a, - 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x4a, 0x4f, - 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x5f, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, - 0x14, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x45, 0x43, - 0x55, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x4a, 0x4f, 0x42, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x17, - 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, - 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x4a, 0x4f, 0x42, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x05, 0x32, - 0xfe, 0x16, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x58, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x23, 0x2e, 0x70, - 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x0e, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x28, 0x2e, 0x70, 0x6f, - 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x79, 0x0a, 0x14, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x2e, 0x70, 0x6f, 0x77, - 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x70, 0x6f, 0x77, + 0x15, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x60, 0x0a, 0x1d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x1a, 0x6c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x44, 0x65, 0x61, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, + 0x6c, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x43, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x65, 0x63, + 0x65, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x69, 0x65, + 0x63, 0x65, 0x43, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x45, 0x70, 0x6f, 0x63, + 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x45, 0x70, 0x6f, + 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, + 0x0a, 0x07, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x70, 0x6f, + 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb4, 0x02, 0x0a, + 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x61, + 0x70, 0x69, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x69, + 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x63, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x64, + 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x64, 0x65, 0x61, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x0b, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x0a, 0x64, 0x65, 0x61, 0x6c, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x22, 0x5e, 0x0a, 0x09, 0x44, 0x65, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, + 0x43, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x61, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, + 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x61, 0x6c, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, + 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x64, + 0x61, 0x74, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x64, 0x61, 0x74, 0x61, 0x43, 0x69, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x22, 0xf8, 0x02, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, + 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x43, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, + 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x70, 0x69, 0x65, 0x63, 0x65, 0x43, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x26, 0x0a, 0x0f, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x45, + 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0xb7, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x69, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3f, 0x0a, 0x09, 0x64, 0x65, 0x61, 0x6c, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x6f, + 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x08, 0x64, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x80, 0x02, 0x0a, 0x11, 0x52, 0x65, + 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x70, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x3a, 0x0a, 0x19, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x63, 0x72, 0x65, + 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x70, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, + 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x65, + 0x72, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0x86, 0x01, 0x0a, + 0x13, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, + 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x64, 0x65, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, + 0x76, 0x61, 0x6c, 0x44, 0x65, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x64, 0x65, 0x61, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x2a, 0xa0, 0x01, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x15, 0x0a, 0x11, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x51, 0x55, + 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, + 0x12, 0x15, 0x0a, 0x11, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x04, + 0x12, 0x16, 0x0a, 0x12, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, + 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x05, 0x32, 0xd5, 0x17, 0x0a, 0x0b, 0x55, 0x73, 0x65, + 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x23, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x67, 0x0a, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x28, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, + 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x79, 0x0a, 0x14, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x82, 0x01, - 0x0a, 0x17, 0x53, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x2e, 0x70, 0x6f, 0x77, 0x65, - 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x70, + 0x66, 0x69, 0x67, 0x12, 0x2e, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x82, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x31, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x12, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x2c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x4f, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x20, 0x2e, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x73, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, - 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x12, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x67, - 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x5e, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6c, + 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x4e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x6f, + 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, + 0x01, 0x12, 0x55, 0x0a, 0x08, 0x53, 0x74, 0x61, 0x67, 0x65, 0x43, 0x69, 0x64, 0x12, 0x22, 0x2e, + 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x43, 0x69, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x43, 0x69, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, @@ -5473,7 +5567,7 @@ func file_powergate_user_v1_user_proto_rawDescGZIP() []byte { } var file_powergate_user_v1_user_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_powergate_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 80) +var file_powergate_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 82) var file_powergate_user_v1_user_proto_goTypes = []interface{}{ (JobStatus)(0), // 0: powergate.user.v1.JobStatus (*BuildInfoRequest)(nil), // 1: powergate.user.v1.BuildInfoRequest @@ -5486,179 +5580,183 @@ var file_powergate_user_v1_user_proto_goTypes = []interface{}{ (*SetDefaultStorageConfigResponse)(nil), // 8: powergate.user.v1.SetDefaultStorageConfigResponse (*StageRequest)(nil), // 9: powergate.user.v1.StageRequest (*StageResponse)(nil), // 10: powergate.user.v1.StageResponse - (*ApplyStorageConfigRequest)(nil), // 11: powergate.user.v1.ApplyStorageConfigRequest - (*ApplyStorageConfigResponse)(nil), // 12: powergate.user.v1.ApplyStorageConfigResponse - (*ReplaceDataRequest)(nil), // 13: powergate.user.v1.ReplaceDataRequest - (*ReplaceDataResponse)(nil), // 14: powergate.user.v1.ReplaceDataResponse - (*GetRequest)(nil), // 15: powergate.user.v1.GetRequest - (*GetResponse)(nil), // 16: powergate.user.v1.GetResponse - (*RemoveRequest)(nil), // 17: powergate.user.v1.RemoveRequest - (*RemoveResponse)(nil), // 18: powergate.user.v1.RemoveResponse - (*WatchLogsRequest)(nil), // 19: powergate.user.v1.WatchLogsRequest - (*WatchLogsResponse)(nil), // 20: powergate.user.v1.WatchLogsResponse - (*CidInfoRequest)(nil), // 21: powergate.user.v1.CidInfoRequest - (*CidInfoResponse)(nil), // 22: powergate.user.v1.CidInfoResponse - (*BalanceRequest)(nil), // 23: powergate.user.v1.BalanceRequest - (*BalanceResponse)(nil), // 24: powergate.user.v1.BalanceResponse - (*NewAddressRequest)(nil), // 25: powergate.user.v1.NewAddressRequest - (*NewAddressResponse)(nil), // 26: powergate.user.v1.NewAddressResponse - (*AddressesRequest)(nil), // 27: powergate.user.v1.AddressesRequest - (*AddressesResponse)(nil), // 28: powergate.user.v1.AddressesResponse - (*SendFilRequest)(nil), // 29: powergate.user.v1.SendFilRequest - (*SendFilResponse)(nil), // 30: powergate.user.v1.SendFilResponse - (*SignMessageRequest)(nil), // 31: powergate.user.v1.SignMessageRequest - (*SignMessageResponse)(nil), // 32: powergate.user.v1.SignMessageResponse - (*VerifyMessageRequest)(nil), // 33: powergate.user.v1.VerifyMessageRequest - (*VerifyMessageResponse)(nil), // 34: powergate.user.v1.VerifyMessageResponse - (*CancelStorageJobRequest)(nil), // 35: powergate.user.v1.CancelStorageJobRequest - (*CancelStorageJobResponse)(nil), // 36: powergate.user.v1.CancelStorageJobResponse - (*StorageJobRequest)(nil), // 37: powergate.user.v1.StorageJobRequest - (*StorageJobResponse)(nil), // 38: powergate.user.v1.StorageJobResponse - (*StorageConfigForJobRequest)(nil), // 39: powergate.user.v1.StorageConfigForJobRequest - (*StorageConfigForJobResponse)(nil), // 40: powergate.user.v1.StorageConfigForJobResponse - (*QueuedStorageJobsRequest)(nil), // 41: powergate.user.v1.QueuedStorageJobsRequest - (*QueuedStorageJobsResponse)(nil), // 42: powergate.user.v1.QueuedStorageJobsResponse - (*ExecutingStorageJobsRequest)(nil), // 43: powergate.user.v1.ExecutingStorageJobsRequest - (*ExecutingStorageJobsResponse)(nil), // 44: powergate.user.v1.ExecutingStorageJobsResponse - (*LatestFinalStorageJobsRequest)(nil), // 45: powergate.user.v1.LatestFinalStorageJobsRequest - (*LatestFinalStorageJobsResponse)(nil), // 46: powergate.user.v1.LatestFinalStorageJobsResponse - (*LatestSuccessfulStorageJobsRequest)(nil), // 47: powergate.user.v1.LatestSuccessfulStorageJobsRequest - (*LatestSuccessfulStorageJobsResponse)(nil), // 48: powergate.user.v1.LatestSuccessfulStorageJobsResponse - (*StorageJobsSummaryRequest)(nil), // 49: powergate.user.v1.StorageJobsSummaryRequest - (*StorageJobsSummaryResponse)(nil), // 50: powergate.user.v1.StorageJobsSummaryResponse - (*WatchStorageJobsRequest)(nil), // 51: powergate.user.v1.WatchStorageJobsRequest - (*WatchStorageJobsResponse)(nil), // 52: powergate.user.v1.WatchStorageJobsResponse - (*StorageDealRecordsRequest)(nil), // 53: powergate.user.v1.StorageDealRecordsRequest - (*StorageDealRecordsResponse)(nil), // 54: powergate.user.v1.StorageDealRecordsResponse - (*RetrievalDealRecordsRequest)(nil), // 55: powergate.user.v1.RetrievalDealRecordsRequest - (*RetrievalDealRecordsResponse)(nil), // 56: powergate.user.v1.RetrievalDealRecordsResponse - (*JobCounts)(nil), // 57: powergate.user.v1.JobCounts - (*AddrInfo)(nil), // 58: powergate.user.v1.AddrInfo - (*IpfsConfig)(nil), // 59: powergate.user.v1.IpfsConfig - (*HotConfig)(nil), // 60: powergate.user.v1.HotConfig - (*FilRenew)(nil), // 61: powergate.user.v1.FilRenew - (*FilConfig)(nil), // 62: powergate.user.v1.FilConfig - (*ColdConfig)(nil), // 63: powergate.user.v1.ColdConfig - (*StorageConfig)(nil), // 64: powergate.user.v1.StorageConfig - (*IpfsHotInfo)(nil), // 65: powergate.user.v1.IpfsHotInfo - (*HotInfo)(nil), // 66: powergate.user.v1.HotInfo - (*FilStorage)(nil), // 67: powergate.user.v1.FilStorage - (*FilInfo)(nil), // 68: powergate.user.v1.FilInfo - (*ColdInfo)(nil), // 69: powergate.user.v1.ColdInfo - (*StorageInfo)(nil), // 70: powergate.user.v1.StorageInfo - (*CidInfo)(nil), // 71: powergate.user.v1.CidInfo - (*DealInfo)(nil), // 72: powergate.user.v1.DealInfo - (*StorageJob)(nil), // 73: powergate.user.v1.StorageJob - (*DealError)(nil), // 74: powergate.user.v1.DealError - (*LogEntry)(nil), // 75: powergate.user.v1.LogEntry - (*DealRecordsConfig)(nil), // 76: powergate.user.v1.DealRecordsConfig - (*StorageDealInfo)(nil), // 77: powergate.user.v1.StorageDealInfo - (*StorageDealRecord)(nil), // 78: powergate.user.v1.StorageDealRecord - (*RetrievalDealInfo)(nil), // 79: powergate.user.v1.RetrievalDealInfo - (*RetrievalDealRecord)(nil), // 80: powergate.user.v1.RetrievalDealRecord + (*StageCidRequest)(nil), // 11: powergate.user.v1.StageCidRequest + (*StageCidResponse)(nil), // 12: powergate.user.v1.StageCidResponse + (*ApplyStorageConfigRequest)(nil), // 13: powergate.user.v1.ApplyStorageConfigRequest + (*ApplyStorageConfigResponse)(nil), // 14: powergate.user.v1.ApplyStorageConfigResponse + (*ReplaceDataRequest)(nil), // 15: powergate.user.v1.ReplaceDataRequest + (*ReplaceDataResponse)(nil), // 16: powergate.user.v1.ReplaceDataResponse + (*GetRequest)(nil), // 17: powergate.user.v1.GetRequest + (*GetResponse)(nil), // 18: powergate.user.v1.GetResponse + (*RemoveRequest)(nil), // 19: powergate.user.v1.RemoveRequest + (*RemoveResponse)(nil), // 20: powergate.user.v1.RemoveResponse + (*WatchLogsRequest)(nil), // 21: powergate.user.v1.WatchLogsRequest + (*WatchLogsResponse)(nil), // 22: powergate.user.v1.WatchLogsResponse + (*CidInfoRequest)(nil), // 23: powergate.user.v1.CidInfoRequest + (*CidInfoResponse)(nil), // 24: powergate.user.v1.CidInfoResponse + (*BalanceRequest)(nil), // 25: powergate.user.v1.BalanceRequest + (*BalanceResponse)(nil), // 26: powergate.user.v1.BalanceResponse + (*NewAddressRequest)(nil), // 27: powergate.user.v1.NewAddressRequest + (*NewAddressResponse)(nil), // 28: powergate.user.v1.NewAddressResponse + (*AddressesRequest)(nil), // 29: powergate.user.v1.AddressesRequest + (*AddressesResponse)(nil), // 30: powergate.user.v1.AddressesResponse + (*SendFilRequest)(nil), // 31: powergate.user.v1.SendFilRequest + (*SendFilResponse)(nil), // 32: powergate.user.v1.SendFilResponse + (*SignMessageRequest)(nil), // 33: powergate.user.v1.SignMessageRequest + (*SignMessageResponse)(nil), // 34: powergate.user.v1.SignMessageResponse + (*VerifyMessageRequest)(nil), // 35: powergate.user.v1.VerifyMessageRequest + (*VerifyMessageResponse)(nil), // 36: powergate.user.v1.VerifyMessageResponse + (*CancelStorageJobRequest)(nil), // 37: powergate.user.v1.CancelStorageJobRequest + (*CancelStorageJobResponse)(nil), // 38: powergate.user.v1.CancelStorageJobResponse + (*StorageJobRequest)(nil), // 39: powergate.user.v1.StorageJobRequest + (*StorageJobResponse)(nil), // 40: powergate.user.v1.StorageJobResponse + (*StorageConfigForJobRequest)(nil), // 41: powergate.user.v1.StorageConfigForJobRequest + (*StorageConfigForJobResponse)(nil), // 42: powergate.user.v1.StorageConfigForJobResponse + (*QueuedStorageJobsRequest)(nil), // 43: powergate.user.v1.QueuedStorageJobsRequest + (*QueuedStorageJobsResponse)(nil), // 44: powergate.user.v1.QueuedStorageJobsResponse + (*ExecutingStorageJobsRequest)(nil), // 45: powergate.user.v1.ExecutingStorageJobsRequest + (*ExecutingStorageJobsResponse)(nil), // 46: powergate.user.v1.ExecutingStorageJobsResponse + (*LatestFinalStorageJobsRequest)(nil), // 47: powergate.user.v1.LatestFinalStorageJobsRequest + (*LatestFinalStorageJobsResponse)(nil), // 48: powergate.user.v1.LatestFinalStorageJobsResponse + (*LatestSuccessfulStorageJobsRequest)(nil), // 49: powergate.user.v1.LatestSuccessfulStorageJobsRequest + (*LatestSuccessfulStorageJobsResponse)(nil), // 50: powergate.user.v1.LatestSuccessfulStorageJobsResponse + (*StorageJobsSummaryRequest)(nil), // 51: powergate.user.v1.StorageJobsSummaryRequest + (*StorageJobsSummaryResponse)(nil), // 52: powergate.user.v1.StorageJobsSummaryResponse + (*WatchStorageJobsRequest)(nil), // 53: powergate.user.v1.WatchStorageJobsRequest + (*WatchStorageJobsResponse)(nil), // 54: powergate.user.v1.WatchStorageJobsResponse + (*StorageDealRecordsRequest)(nil), // 55: powergate.user.v1.StorageDealRecordsRequest + (*StorageDealRecordsResponse)(nil), // 56: powergate.user.v1.StorageDealRecordsResponse + (*RetrievalDealRecordsRequest)(nil), // 57: powergate.user.v1.RetrievalDealRecordsRequest + (*RetrievalDealRecordsResponse)(nil), // 58: powergate.user.v1.RetrievalDealRecordsResponse + (*JobCounts)(nil), // 59: powergate.user.v1.JobCounts + (*AddrInfo)(nil), // 60: powergate.user.v1.AddrInfo + (*IpfsConfig)(nil), // 61: powergate.user.v1.IpfsConfig + (*HotConfig)(nil), // 62: powergate.user.v1.HotConfig + (*FilRenew)(nil), // 63: powergate.user.v1.FilRenew + (*FilConfig)(nil), // 64: powergate.user.v1.FilConfig + (*ColdConfig)(nil), // 65: powergate.user.v1.ColdConfig + (*StorageConfig)(nil), // 66: powergate.user.v1.StorageConfig + (*IpfsHotInfo)(nil), // 67: powergate.user.v1.IpfsHotInfo + (*HotInfo)(nil), // 68: powergate.user.v1.HotInfo + (*FilStorage)(nil), // 69: powergate.user.v1.FilStorage + (*FilInfo)(nil), // 70: powergate.user.v1.FilInfo + (*ColdInfo)(nil), // 71: powergate.user.v1.ColdInfo + (*StorageInfo)(nil), // 72: powergate.user.v1.StorageInfo + (*CidInfo)(nil), // 73: powergate.user.v1.CidInfo + (*DealInfo)(nil), // 74: powergate.user.v1.DealInfo + (*StorageJob)(nil), // 75: powergate.user.v1.StorageJob + (*DealError)(nil), // 76: powergate.user.v1.DealError + (*LogEntry)(nil), // 77: powergate.user.v1.LogEntry + (*DealRecordsConfig)(nil), // 78: powergate.user.v1.DealRecordsConfig + (*StorageDealInfo)(nil), // 79: powergate.user.v1.StorageDealInfo + (*StorageDealRecord)(nil), // 80: powergate.user.v1.StorageDealRecord + (*RetrievalDealInfo)(nil), // 81: powergate.user.v1.RetrievalDealInfo + (*RetrievalDealRecord)(nil), // 82: powergate.user.v1.RetrievalDealRecord } var file_powergate_user_v1_user_proto_depIdxs = []int32{ - 64, // 0: powergate.user.v1.DefaultStorageConfigResponse.default_storage_config:type_name -> powergate.user.v1.StorageConfig - 64, // 1: powergate.user.v1.SetDefaultStorageConfigRequest.config:type_name -> powergate.user.v1.StorageConfig - 64, // 2: powergate.user.v1.ApplyStorageConfigRequest.config:type_name -> powergate.user.v1.StorageConfig - 75, // 3: powergate.user.v1.WatchLogsResponse.log_entry:type_name -> powergate.user.v1.LogEntry - 71, // 4: powergate.user.v1.CidInfoResponse.cid_infos:type_name -> powergate.user.v1.CidInfo - 58, // 5: powergate.user.v1.AddressesResponse.addresses:type_name -> powergate.user.v1.AddrInfo - 73, // 6: powergate.user.v1.StorageJobResponse.storage_job:type_name -> powergate.user.v1.StorageJob - 64, // 7: powergate.user.v1.StorageConfigForJobResponse.storage_config:type_name -> powergate.user.v1.StorageConfig - 73, // 8: powergate.user.v1.QueuedStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 9: powergate.user.v1.ExecutingStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 10: powergate.user.v1.LatestFinalStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 11: powergate.user.v1.LatestSuccessfulStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob - 57, // 12: powergate.user.v1.StorageJobsSummaryResponse.job_counts:type_name -> powergate.user.v1.JobCounts - 73, // 13: powergate.user.v1.StorageJobsSummaryResponse.queued_storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 14: powergate.user.v1.StorageJobsSummaryResponse.executing_storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 15: powergate.user.v1.StorageJobsSummaryResponse.latest_final_storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 16: powergate.user.v1.StorageJobsSummaryResponse.latest_successful_storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 17: powergate.user.v1.WatchStorageJobsResponse.storage_job:type_name -> powergate.user.v1.StorageJob - 76, // 18: powergate.user.v1.StorageDealRecordsRequest.config:type_name -> powergate.user.v1.DealRecordsConfig - 78, // 19: powergate.user.v1.StorageDealRecordsResponse.records:type_name -> powergate.user.v1.StorageDealRecord - 76, // 20: powergate.user.v1.RetrievalDealRecordsRequest.config:type_name -> powergate.user.v1.DealRecordsConfig - 80, // 21: powergate.user.v1.RetrievalDealRecordsResponse.records:type_name -> powergate.user.v1.RetrievalDealRecord - 59, // 22: powergate.user.v1.HotConfig.ipfs:type_name -> powergate.user.v1.IpfsConfig - 61, // 23: powergate.user.v1.FilConfig.renew:type_name -> powergate.user.v1.FilRenew - 62, // 24: powergate.user.v1.ColdConfig.filecoin:type_name -> powergate.user.v1.FilConfig - 60, // 25: powergate.user.v1.StorageConfig.hot:type_name -> powergate.user.v1.HotConfig - 63, // 26: powergate.user.v1.StorageConfig.cold:type_name -> powergate.user.v1.ColdConfig - 65, // 27: powergate.user.v1.HotInfo.ipfs:type_name -> powergate.user.v1.IpfsHotInfo - 67, // 28: powergate.user.v1.FilInfo.proposals:type_name -> powergate.user.v1.FilStorage - 68, // 29: powergate.user.v1.ColdInfo.filecoin:type_name -> powergate.user.v1.FilInfo - 66, // 30: powergate.user.v1.StorageInfo.hot:type_name -> powergate.user.v1.HotInfo - 69, // 31: powergate.user.v1.StorageInfo.cold:type_name -> powergate.user.v1.ColdInfo - 64, // 32: powergate.user.v1.CidInfo.latest_pushed_storage_config:type_name -> powergate.user.v1.StorageConfig - 70, // 33: powergate.user.v1.CidInfo.current_storage_info:type_name -> powergate.user.v1.StorageInfo - 73, // 34: powergate.user.v1.CidInfo.queued_storage_jobs:type_name -> powergate.user.v1.StorageJob - 73, // 35: powergate.user.v1.CidInfo.executing_storage_job:type_name -> powergate.user.v1.StorageJob - 73, // 36: powergate.user.v1.CidInfo.latest_final_storage_job:type_name -> powergate.user.v1.StorageJob - 73, // 37: powergate.user.v1.CidInfo.latest_successful_storage_job:type_name -> powergate.user.v1.StorageJob + 66, // 0: powergate.user.v1.DefaultStorageConfigResponse.default_storage_config:type_name -> powergate.user.v1.StorageConfig + 66, // 1: powergate.user.v1.SetDefaultStorageConfigRequest.config:type_name -> powergate.user.v1.StorageConfig + 66, // 2: powergate.user.v1.ApplyStorageConfigRequest.config:type_name -> powergate.user.v1.StorageConfig + 77, // 3: powergate.user.v1.WatchLogsResponse.log_entry:type_name -> powergate.user.v1.LogEntry + 73, // 4: powergate.user.v1.CidInfoResponse.cid_infos:type_name -> powergate.user.v1.CidInfo + 60, // 5: powergate.user.v1.AddressesResponse.addresses:type_name -> powergate.user.v1.AddrInfo + 75, // 6: powergate.user.v1.StorageJobResponse.storage_job:type_name -> powergate.user.v1.StorageJob + 66, // 7: powergate.user.v1.StorageConfigForJobResponse.storage_config:type_name -> powergate.user.v1.StorageConfig + 75, // 8: powergate.user.v1.QueuedStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 9: powergate.user.v1.ExecutingStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 10: powergate.user.v1.LatestFinalStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 11: powergate.user.v1.LatestSuccessfulStorageJobsResponse.storage_jobs:type_name -> powergate.user.v1.StorageJob + 59, // 12: powergate.user.v1.StorageJobsSummaryResponse.job_counts:type_name -> powergate.user.v1.JobCounts + 75, // 13: powergate.user.v1.StorageJobsSummaryResponse.queued_storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 14: powergate.user.v1.StorageJobsSummaryResponse.executing_storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 15: powergate.user.v1.StorageJobsSummaryResponse.latest_final_storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 16: powergate.user.v1.StorageJobsSummaryResponse.latest_successful_storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 17: powergate.user.v1.WatchStorageJobsResponse.storage_job:type_name -> powergate.user.v1.StorageJob + 78, // 18: powergate.user.v1.StorageDealRecordsRequest.config:type_name -> powergate.user.v1.DealRecordsConfig + 80, // 19: powergate.user.v1.StorageDealRecordsResponse.records:type_name -> powergate.user.v1.StorageDealRecord + 78, // 20: powergate.user.v1.RetrievalDealRecordsRequest.config:type_name -> powergate.user.v1.DealRecordsConfig + 82, // 21: powergate.user.v1.RetrievalDealRecordsResponse.records:type_name -> powergate.user.v1.RetrievalDealRecord + 61, // 22: powergate.user.v1.HotConfig.ipfs:type_name -> powergate.user.v1.IpfsConfig + 63, // 23: powergate.user.v1.FilConfig.renew:type_name -> powergate.user.v1.FilRenew + 64, // 24: powergate.user.v1.ColdConfig.filecoin:type_name -> powergate.user.v1.FilConfig + 62, // 25: powergate.user.v1.StorageConfig.hot:type_name -> powergate.user.v1.HotConfig + 65, // 26: powergate.user.v1.StorageConfig.cold:type_name -> powergate.user.v1.ColdConfig + 67, // 27: powergate.user.v1.HotInfo.ipfs:type_name -> powergate.user.v1.IpfsHotInfo + 69, // 28: powergate.user.v1.FilInfo.proposals:type_name -> powergate.user.v1.FilStorage + 70, // 29: powergate.user.v1.ColdInfo.filecoin:type_name -> powergate.user.v1.FilInfo + 68, // 30: powergate.user.v1.StorageInfo.hot:type_name -> powergate.user.v1.HotInfo + 71, // 31: powergate.user.v1.StorageInfo.cold:type_name -> powergate.user.v1.ColdInfo + 66, // 32: powergate.user.v1.CidInfo.latest_pushed_storage_config:type_name -> powergate.user.v1.StorageConfig + 72, // 33: powergate.user.v1.CidInfo.current_storage_info:type_name -> powergate.user.v1.StorageInfo + 75, // 34: powergate.user.v1.CidInfo.queued_storage_jobs:type_name -> powergate.user.v1.StorageJob + 75, // 35: powergate.user.v1.CidInfo.executing_storage_job:type_name -> powergate.user.v1.StorageJob + 75, // 36: powergate.user.v1.CidInfo.latest_final_storage_job:type_name -> powergate.user.v1.StorageJob + 75, // 37: powergate.user.v1.CidInfo.latest_successful_storage_job:type_name -> powergate.user.v1.StorageJob 0, // 38: powergate.user.v1.StorageJob.status:type_name -> powergate.user.v1.JobStatus - 72, // 39: powergate.user.v1.StorageJob.deal_info:type_name -> powergate.user.v1.DealInfo - 74, // 40: powergate.user.v1.StorageJob.deal_errors:type_name -> powergate.user.v1.DealError - 77, // 41: powergate.user.v1.StorageDealRecord.deal_info:type_name -> powergate.user.v1.StorageDealInfo - 79, // 42: powergate.user.v1.RetrievalDealRecord.deal_info:type_name -> powergate.user.v1.RetrievalDealInfo + 74, // 39: powergate.user.v1.StorageJob.deal_info:type_name -> powergate.user.v1.DealInfo + 76, // 40: powergate.user.v1.StorageJob.deal_errors:type_name -> powergate.user.v1.DealError + 79, // 41: powergate.user.v1.StorageDealRecord.deal_info:type_name -> powergate.user.v1.StorageDealInfo + 81, // 42: powergate.user.v1.RetrievalDealRecord.deal_info:type_name -> powergate.user.v1.RetrievalDealInfo 1, // 43: powergate.user.v1.UserService.BuildInfo:input_type -> powergate.user.v1.BuildInfoRequest 3, // 44: powergate.user.v1.UserService.UserIdentifier:input_type -> powergate.user.v1.UserIdentifierRequest 5, // 45: powergate.user.v1.UserService.DefaultStorageConfig:input_type -> powergate.user.v1.DefaultStorageConfigRequest 7, // 46: powergate.user.v1.UserService.SetDefaultStorageConfig:input_type -> powergate.user.v1.SetDefaultStorageConfigRequest - 11, // 47: powergate.user.v1.UserService.ApplyStorageConfig:input_type -> powergate.user.v1.ApplyStorageConfigRequest - 17, // 48: powergate.user.v1.UserService.Remove:input_type -> powergate.user.v1.RemoveRequest + 13, // 47: powergate.user.v1.UserService.ApplyStorageConfig:input_type -> powergate.user.v1.ApplyStorageConfigRequest + 19, // 48: powergate.user.v1.UserService.Remove:input_type -> powergate.user.v1.RemoveRequest 9, // 49: powergate.user.v1.UserService.Stage:input_type -> powergate.user.v1.StageRequest - 13, // 50: powergate.user.v1.UserService.ReplaceData:input_type -> powergate.user.v1.ReplaceDataRequest - 15, // 51: powergate.user.v1.UserService.Get:input_type -> powergate.user.v1.GetRequest - 19, // 52: powergate.user.v1.UserService.WatchLogs:input_type -> powergate.user.v1.WatchLogsRequest - 21, // 53: powergate.user.v1.UserService.CidInfo:input_type -> powergate.user.v1.CidInfoRequest - 23, // 54: powergate.user.v1.UserService.Balance:input_type -> powergate.user.v1.BalanceRequest - 25, // 55: powergate.user.v1.UserService.NewAddress:input_type -> powergate.user.v1.NewAddressRequest - 27, // 56: powergate.user.v1.UserService.Addresses:input_type -> powergate.user.v1.AddressesRequest - 29, // 57: powergate.user.v1.UserService.SendFil:input_type -> powergate.user.v1.SendFilRequest - 31, // 58: powergate.user.v1.UserService.SignMessage:input_type -> powergate.user.v1.SignMessageRequest - 33, // 59: powergate.user.v1.UserService.VerifyMessage:input_type -> powergate.user.v1.VerifyMessageRequest - 37, // 60: powergate.user.v1.UserService.StorageJob:input_type -> powergate.user.v1.StorageJobRequest - 39, // 61: powergate.user.v1.UserService.StorageConfigForJob:input_type -> powergate.user.v1.StorageConfigForJobRequest - 41, // 62: powergate.user.v1.UserService.QueuedStorageJobs:input_type -> powergate.user.v1.QueuedStorageJobsRequest - 43, // 63: powergate.user.v1.UserService.ExecutingStorageJobs:input_type -> powergate.user.v1.ExecutingStorageJobsRequest - 45, // 64: powergate.user.v1.UserService.LatestFinalStorageJobs:input_type -> powergate.user.v1.LatestFinalStorageJobsRequest - 47, // 65: powergate.user.v1.UserService.LatestSuccessfulStorageJobs:input_type -> powergate.user.v1.LatestSuccessfulStorageJobsRequest - 49, // 66: powergate.user.v1.UserService.StorageJobsSummary:input_type -> powergate.user.v1.StorageJobsSummaryRequest - 51, // 67: powergate.user.v1.UserService.WatchStorageJobs:input_type -> powergate.user.v1.WatchStorageJobsRequest - 35, // 68: powergate.user.v1.UserService.CancelStorageJob:input_type -> powergate.user.v1.CancelStorageJobRequest - 53, // 69: powergate.user.v1.UserService.StorageDealRecords:input_type -> powergate.user.v1.StorageDealRecordsRequest - 55, // 70: powergate.user.v1.UserService.RetrievalDealRecords:input_type -> powergate.user.v1.RetrievalDealRecordsRequest - 2, // 71: powergate.user.v1.UserService.BuildInfo:output_type -> powergate.user.v1.BuildInfoResponse - 4, // 72: powergate.user.v1.UserService.UserIdentifier:output_type -> powergate.user.v1.UserIdentifierResponse - 6, // 73: powergate.user.v1.UserService.DefaultStorageConfig:output_type -> powergate.user.v1.DefaultStorageConfigResponse - 8, // 74: powergate.user.v1.UserService.SetDefaultStorageConfig:output_type -> powergate.user.v1.SetDefaultStorageConfigResponse - 12, // 75: powergate.user.v1.UserService.ApplyStorageConfig:output_type -> powergate.user.v1.ApplyStorageConfigResponse - 18, // 76: powergate.user.v1.UserService.Remove:output_type -> powergate.user.v1.RemoveResponse - 10, // 77: powergate.user.v1.UserService.Stage:output_type -> powergate.user.v1.StageResponse - 14, // 78: powergate.user.v1.UserService.ReplaceData:output_type -> powergate.user.v1.ReplaceDataResponse - 16, // 79: powergate.user.v1.UserService.Get:output_type -> powergate.user.v1.GetResponse - 20, // 80: powergate.user.v1.UserService.WatchLogs:output_type -> powergate.user.v1.WatchLogsResponse - 22, // 81: powergate.user.v1.UserService.CidInfo:output_type -> powergate.user.v1.CidInfoResponse - 24, // 82: powergate.user.v1.UserService.Balance:output_type -> powergate.user.v1.BalanceResponse - 26, // 83: powergate.user.v1.UserService.NewAddress:output_type -> powergate.user.v1.NewAddressResponse - 28, // 84: powergate.user.v1.UserService.Addresses:output_type -> powergate.user.v1.AddressesResponse - 30, // 85: powergate.user.v1.UserService.SendFil:output_type -> powergate.user.v1.SendFilResponse - 32, // 86: powergate.user.v1.UserService.SignMessage:output_type -> powergate.user.v1.SignMessageResponse - 34, // 87: powergate.user.v1.UserService.VerifyMessage:output_type -> powergate.user.v1.VerifyMessageResponse - 38, // 88: powergate.user.v1.UserService.StorageJob:output_type -> powergate.user.v1.StorageJobResponse - 40, // 89: powergate.user.v1.UserService.StorageConfigForJob:output_type -> powergate.user.v1.StorageConfigForJobResponse - 42, // 90: powergate.user.v1.UserService.QueuedStorageJobs:output_type -> powergate.user.v1.QueuedStorageJobsResponse - 44, // 91: powergate.user.v1.UserService.ExecutingStorageJobs:output_type -> powergate.user.v1.ExecutingStorageJobsResponse - 46, // 92: powergate.user.v1.UserService.LatestFinalStorageJobs:output_type -> powergate.user.v1.LatestFinalStorageJobsResponse - 48, // 93: powergate.user.v1.UserService.LatestSuccessfulStorageJobs:output_type -> powergate.user.v1.LatestSuccessfulStorageJobsResponse - 50, // 94: powergate.user.v1.UserService.StorageJobsSummary:output_type -> powergate.user.v1.StorageJobsSummaryResponse - 52, // 95: powergate.user.v1.UserService.WatchStorageJobs:output_type -> powergate.user.v1.WatchStorageJobsResponse - 36, // 96: powergate.user.v1.UserService.CancelStorageJob:output_type -> powergate.user.v1.CancelStorageJobResponse - 54, // 97: powergate.user.v1.UserService.StorageDealRecords:output_type -> powergate.user.v1.StorageDealRecordsResponse - 56, // 98: powergate.user.v1.UserService.RetrievalDealRecords:output_type -> powergate.user.v1.RetrievalDealRecordsResponse - 71, // [71:99] is the sub-list for method output_type - 43, // [43:71] is the sub-list for method input_type + 11, // 50: powergate.user.v1.UserService.StageCid:input_type -> powergate.user.v1.StageCidRequest + 15, // 51: powergate.user.v1.UserService.ReplaceData:input_type -> powergate.user.v1.ReplaceDataRequest + 17, // 52: powergate.user.v1.UserService.Get:input_type -> powergate.user.v1.GetRequest + 21, // 53: powergate.user.v1.UserService.WatchLogs:input_type -> powergate.user.v1.WatchLogsRequest + 23, // 54: powergate.user.v1.UserService.CidInfo:input_type -> powergate.user.v1.CidInfoRequest + 25, // 55: powergate.user.v1.UserService.Balance:input_type -> powergate.user.v1.BalanceRequest + 27, // 56: powergate.user.v1.UserService.NewAddress:input_type -> powergate.user.v1.NewAddressRequest + 29, // 57: powergate.user.v1.UserService.Addresses:input_type -> powergate.user.v1.AddressesRequest + 31, // 58: powergate.user.v1.UserService.SendFil:input_type -> powergate.user.v1.SendFilRequest + 33, // 59: powergate.user.v1.UserService.SignMessage:input_type -> powergate.user.v1.SignMessageRequest + 35, // 60: powergate.user.v1.UserService.VerifyMessage:input_type -> powergate.user.v1.VerifyMessageRequest + 39, // 61: powergate.user.v1.UserService.StorageJob:input_type -> powergate.user.v1.StorageJobRequest + 41, // 62: powergate.user.v1.UserService.StorageConfigForJob:input_type -> powergate.user.v1.StorageConfigForJobRequest + 43, // 63: powergate.user.v1.UserService.QueuedStorageJobs:input_type -> powergate.user.v1.QueuedStorageJobsRequest + 45, // 64: powergate.user.v1.UserService.ExecutingStorageJobs:input_type -> powergate.user.v1.ExecutingStorageJobsRequest + 47, // 65: powergate.user.v1.UserService.LatestFinalStorageJobs:input_type -> powergate.user.v1.LatestFinalStorageJobsRequest + 49, // 66: powergate.user.v1.UserService.LatestSuccessfulStorageJobs:input_type -> powergate.user.v1.LatestSuccessfulStorageJobsRequest + 51, // 67: powergate.user.v1.UserService.StorageJobsSummary:input_type -> powergate.user.v1.StorageJobsSummaryRequest + 53, // 68: powergate.user.v1.UserService.WatchStorageJobs:input_type -> powergate.user.v1.WatchStorageJobsRequest + 37, // 69: powergate.user.v1.UserService.CancelStorageJob:input_type -> powergate.user.v1.CancelStorageJobRequest + 55, // 70: powergate.user.v1.UserService.StorageDealRecords:input_type -> powergate.user.v1.StorageDealRecordsRequest + 57, // 71: powergate.user.v1.UserService.RetrievalDealRecords:input_type -> powergate.user.v1.RetrievalDealRecordsRequest + 2, // 72: powergate.user.v1.UserService.BuildInfo:output_type -> powergate.user.v1.BuildInfoResponse + 4, // 73: powergate.user.v1.UserService.UserIdentifier:output_type -> powergate.user.v1.UserIdentifierResponse + 6, // 74: powergate.user.v1.UserService.DefaultStorageConfig:output_type -> powergate.user.v1.DefaultStorageConfigResponse + 8, // 75: powergate.user.v1.UserService.SetDefaultStorageConfig:output_type -> powergate.user.v1.SetDefaultStorageConfigResponse + 14, // 76: powergate.user.v1.UserService.ApplyStorageConfig:output_type -> powergate.user.v1.ApplyStorageConfigResponse + 20, // 77: powergate.user.v1.UserService.Remove:output_type -> powergate.user.v1.RemoveResponse + 10, // 78: powergate.user.v1.UserService.Stage:output_type -> powergate.user.v1.StageResponse + 12, // 79: powergate.user.v1.UserService.StageCid:output_type -> powergate.user.v1.StageCidResponse + 16, // 80: powergate.user.v1.UserService.ReplaceData:output_type -> powergate.user.v1.ReplaceDataResponse + 18, // 81: powergate.user.v1.UserService.Get:output_type -> powergate.user.v1.GetResponse + 22, // 82: powergate.user.v1.UserService.WatchLogs:output_type -> powergate.user.v1.WatchLogsResponse + 24, // 83: powergate.user.v1.UserService.CidInfo:output_type -> powergate.user.v1.CidInfoResponse + 26, // 84: powergate.user.v1.UserService.Balance:output_type -> powergate.user.v1.BalanceResponse + 28, // 85: powergate.user.v1.UserService.NewAddress:output_type -> powergate.user.v1.NewAddressResponse + 30, // 86: powergate.user.v1.UserService.Addresses:output_type -> powergate.user.v1.AddressesResponse + 32, // 87: powergate.user.v1.UserService.SendFil:output_type -> powergate.user.v1.SendFilResponse + 34, // 88: powergate.user.v1.UserService.SignMessage:output_type -> powergate.user.v1.SignMessageResponse + 36, // 89: powergate.user.v1.UserService.VerifyMessage:output_type -> powergate.user.v1.VerifyMessageResponse + 40, // 90: powergate.user.v1.UserService.StorageJob:output_type -> powergate.user.v1.StorageJobResponse + 42, // 91: powergate.user.v1.UserService.StorageConfigForJob:output_type -> powergate.user.v1.StorageConfigForJobResponse + 44, // 92: powergate.user.v1.UserService.QueuedStorageJobs:output_type -> powergate.user.v1.QueuedStorageJobsResponse + 46, // 93: powergate.user.v1.UserService.ExecutingStorageJobs:output_type -> powergate.user.v1.ExecutingStorageJobsResponse + 48, // 94: powergate.user.v1.UserService.LatestFinalStorageJobs:output_type -> powergate.user.v1.LatestFinalStorageJobsResponse + 50, // 95: powergate.user.v1.UserService.LatestSuccessfulStorageJobs:output_type -> powergate.user.v1.LatestSuccessfulStorageJobsResponse + 52, // 96: powergate.user.v1.UserService.StorageJobsSummary:output_type -> powergate.user.v1.StorageJobsSummaryResponse + 54, // 97: powergate.user.v1.UserService.WatchStorageJobs:output_type -> powergate.user.v1.WatchStorageJobsResponse + 38, // 98: powergate.user.v1.UserService.CancelStorageJob:output_type -> powergate.user.v1.CancelStorageJobResponse + 56, // 99: powergate.user.v1.UserService.StorageDealRecords:output_type -> powergate.user.v1.StorageDealRecordsResponse + 58, // 100: powergate.user.v1.UserService.RetrievalDealRecords:output_type -> powergate.user.v1.RetrievalDealRecordsResponse + 72, // [72:101] is the sub-list for method output_type + 43, // [43:72] is the sub-list for method input_type 43, // [43:43] is the sub-list for extension type_name 43, // [43:43] is the sub-list for extension extendee 0, // [0:43] is the sub-list for field type_name @@ -5791,7 +5889,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplyStorageConfigRequest); i { + switch v := v.(*StageCidRequest); i { case 0: return &v.state case 1: @@ -5803,7 +5901,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplyStorageConfigResponse); i { + switch v := v.(*StageCidResponse); i { case 0: return &v.state case 1: @@ -5815,7 +5913,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReplaceDataRequest); i { + switch v := v.(*ApplyStorageConfigRequest); i { case 0: return &v.state case 1: @@ -5827,7 +5925,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReplaceDataResponse); i { + switch v := v.(*ApplyStorageConfigResponse); i { case 0: return &v.state case 1: @@ -5839,7 +5937,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRequest); i { + switch v := v.(*ReplaceDataRequest); i { case 0: return &v.state case 1: @@ -5851,7 +5949,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetResponse); i { + switch v := v.(*ReplaceDataResponse); i { case 0: return &v.state case 1: @@ -5863,7 +5961,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RemoveRequest); i { + switch v := v.(*GetRequest); i { case 0: return &v.state case 1: @@ -5875,7 +5973,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RemoveResponse); i { + switch v := v.(*GetResponse); i { case 0: return &v.state case 1: @@ -5887,7 +5985,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WatchLogsRequest); i { + switch v := v.(*RemoveRequest); i { case 0: return &v.state case 1: @@ -5899,7 +5997,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WatchLogsResponse); i { + switch v := v.(*RemoveResponse); i { case 0: return &v.state case 1: @@ -5911,7 +6009,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CidInfoRequest); i { + switch v := v.(*WatchLogsRequest); i { case 0: return &v.state case 1: @@ -5923,7 +6021,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CidInfoResponse); i { + switch v := v.(*WatchLogsResponse); i { case 0: return &v.state case 1: @@ -5935,7 +6033,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BalanceRequest); i { + switch v := v.(*CidInfoRequest); i { case 0: return &v.state case 1: @@ -5947,7 +6045,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BalanceResponse); i { + switch v := v.(*CidInfoResponse); i { case 0: return &v.state case 1: @@ -5959,7 +6057,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewAddressRequest); i { + switch v := v.(*BalanceRequest); i { case 0: return &v.state case 1: @@ -5971,7 +6069,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewAddressResponse); i { + switch v := v.(*BalanceResponse); i { case 0: return &v.state case 1: @@ -5983,7 +6081,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddressesRequest); i { + switch v := v.(*NewAddressRequest); i { case 0: return &v.state case 1: @@ -5995,7 +6093,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddressesResponse); i { + switch v := v.(*NewAddressResponse); i { case 0: return &v.state case 1: @@ -6007,7 +6105,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendFilRequest); i { + switch v := v.(*AddressesRequest); i { case 0: return &v.state case 1: @@ -6019,7 +6117,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendFilResponse); i { + switch v := v.(*AddressesResponse); i { case 0: return &v.state case 1: @@ -6031,7 +6129,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SignMessageRequest); i { + switch v := v.(*SendFilRequest); i { case 0: return &v.state case 1: @@ -6043,7 +6141,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SignMessageResponse); i { + switch v := v.(*SendFilResponse); i { case 0: return &v.state case 1: @@ -6055,7 +6153,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerifyMessageRequest); i { + switch v := v.(*SignMessageRequest); i { case 0: return &v.state case 1: @@ -6067,7 +6165,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerifyMessageResponse); i { + switch v := v.(*SignMessageResponse); i { case 0: return &v.state case 1: @@ -6079,7 +6177,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CancelStorageJobRequest); i { + switch v := v.(*VerifyMessageRequest); i { case 0: return &v.state case 1: @@ -6091,7 +6189,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CancelStorageJobResponse); i { + switch v := v.(*VerifyMessageResponse); i { case 0: return &v.state case 1: @@ -6103,7 +6201,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageJobRequest); i { + switch v := v.(*CancelStorageJobRequest); i { case 0: return &v.state case 1: @@ -6115,7 +6213,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageJobResponse); i { + switch v := v.(*CancelStorageJobResponse); i { case 0: return &v.state case 1: @@ -6127,7 +6225,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageConfigForJobRequest); i { + switch v := v.(*StorageJobRequest); i { case 0: return &v.state case 1: @@ -6139,7 +6237,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageConfigForJobResponse); i { + switch v := v.(*StorageJobResponse); i { case 0: return &v.state case 1: @@ -6151,7 +6249,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueuedStorageJobsRequest); i { + switch v := v.(*StorageConfigForJobRequest); i { case 0: return &v.state case 1: @@ -6163,7 +6261,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueuedStorageJobsResponse); i { + switch v := v.(*StorageConfigForJobResponse); i { case 0: return &v.state case 1: @@ -6175,7 +6273,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutingStorageJobsRequest); i { + switch v := v.(*QueuedStorageJobsRequest); i { case 0: return &v.state case 1: @@ -6187,7 +6285,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutingStorageJobsResponse); i { + switch v := v.(*QueuedStorageJobsResponse); i { case 0: return &v.state case 1: @@ -6199,7 +6297,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LatestFinalStorageJobsRequest); i { + switch v := v.(*ExecutingStorageJobsRequest); i { case 0: return &v.state case 1: @@ -6211,7 +6309,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LatestFinalStorageJobsResponse); i { + switch v := v.(*ExecutingStorageJobsResponse); i { case 0: return &v.state case 1: @@ -6223,7 +6321,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LatestSuccessfulStorageJobsRequest); i { + switch v := v.(*LatestFinalStorageJobsRequest); i { case 0: return &v.state case 1: @@ -6235,7 +6333,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LatestSuccessfulStorageJobsResponse); i { + switch v := v.(*LatestFinalStorageJobsResponse); i { case 0: return &v.state case 1: @@ -6247,7 +6345,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageJobsSummaryRequest); i { + switch v := v.(*LatestSuccessfulStorageJobsRequest); i { case 0: return &v.state case 1: @@ -6259,7 +6357,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageJobsSummaryResponse); i { + switch v := v.(*LatestSuccessfulStorageJobsResponse); i { case 0: return &v.state case 1: @@ -6271,7 +6369,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WatchStorageJobsRequest); i { + switch v := v.(*StorageJobsSummaryRequest); i { case 0: return &v.state case 1: @@ -6283,7 +6381,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WatchStorageJobsResponse); i { + switch v := v.(*StorageJobsSummaryResponse); i { case 0: return &v.state case 1: @@ -6295,7 +6393,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageDealRecordsRequest); i { + switch v := v.(*WatchStorageJobsRequest); i { case 0: return &v.state case 1: @@ -6307,7 +6405,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageDealRecordsResponse); i { + switch v := v.(*WatchStorageJobsResponse); i { case 0: return &v.state case 1: @@ -6319,7 +6417,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RetrievalDealRecordsRequest); i { + switch v := v.(*StorageDealRecordsRequest); i { case 0: return &v.state case 1: @@ -6331,7 +6429,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RetrievalDealRecordsResponse); i { + switch v := v.(*StorageDealRecordsResponse); i { case 0: return &v.state case 1: @@ -6343,7 +6441,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobCounts); i { + switch v := v.(*RetrievalDealRecordsRequest); i { case 0: return &v.state case 1: @@ -6355,7 +6453,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddrInfo); i { + switch v := v.(*RetrievalDealRecordsResponse); i { case 0: return &v.state case 1: @@ -6367,7 +6465,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IpfsConfig); i { + switch v := v.(*JobCounts); i { case 0: return &v.state case 1: @@ -6379,7 +6477,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HotConfig); i { + switch v := v.(*AddrInfo); i { case 0: return &v.state case 1: @@ -6391,7 +6489,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FilRenew); i { + switch v := v.(*IpfsConfig); i { case 0: return &v.state case 1: @@ -6403,7 +6501,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FilConfig); i { + switch v := v.(*HotConfig); i { case 0: return &v.state case 1: @@ -6415,7 +6513,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ColdConfig); i { + switch v := v.(*FilRenew); i { case 0: return &v.state case 1: @@ -6427,7 +6525,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageConfig); i { + switch v := v.(*FilConfig); i { case 0: return &v.state case 1: @@ -6439,7 +6537,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IpfsHotInfo); i { + switch v := v.(*ColdConfig); i { case 0: return &v.state case 1: @@ -6451,7 +6549,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HotInfo); i { + switch v := v.(*StorageConfig); i { case 0: return &v.state case 1: @@ -6463,7 +6561,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FilStorage); i { + switch v := v.(*IpfsHotInfo); i { case 0: return &v.state case 1: @@ -6475,7 +6573,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FilInfo); i { + switch v := v.(*HotInfo); i { case 0: return &v.state case 1: @@ -6487,7 +6585,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ColdInfo); i { + switch v := v.(*FilStorage); i { case 0: return &v.state case 1: @@ -6499,7 +6597,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageInfo); i { + switch v := v.(*FilInfo); i { case 0: return &v.state case 1: @@ -6511,7 +6609,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CidInfo); i { + switch v := v.(*ColdInfo); i { case 0: return &v.state case 1: @@ -6523,7 +6621,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DealInfo); i { + switch v := v.(*StorageInfo); i { case 0: return &v.state case 1: @@ -6535,7 +6633,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageJob); i { + switch v := v.(*CidInfo); i { case 0: return &v.state case 1: @@ -6547,7 +6645,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DealError); i { + switch v := v.(*DealInfo); i { case 0: return &v.state case 1: @@ -6559,7 +6657,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LogEntry); i { + switch v := v.(*StorageJob); i { case 0: return &v.state case 1: @@ -6571,7 +6669,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DealRecordsConfig); i { + switch v := v.(*DealError); i { case 0: return &v.state case 1: @@ -6583,7 +6681,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageDealInfo); i { + switch v := v.(*LogEntry); i { case 0: return &v.state case 1: @@ -6595,7 +6693,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StorageDealRecord); i { + switch v := v.(*DealRecordsConfig); i { case 0: return &v.state case 1: @@ -6607,7 +6705,7 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RetrievalDealInfo); i { + switch v := v.(*StorageDealInfo); i { case 0: return &v.state case 1: @@ -6619,6 +6717,30 @@ func file_powergate_user_v1_user_proto_init() { } } file_powergate_user_v1_user_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StorageDealRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_user_v1_user_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RetrievalDealInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_powergate_user_v1_user_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RetrievalDealRecord); i { case 0: return &v.state @@ -6637,7 +6759,7 @@ func file_powergate_user_v1_user_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_powergate_user_v1_user_proto_rawDesc, NumEnums: 1, - NumMessages: 80, + NumMessages: 82, NumExtensions: 0, NumServices: 1, }, diff --git a/api/gen/powergate/user/v1/user_grpc.pb.go b/api/gen/powergate/user/v1/user_grpc.pb.go index d18084a8a..01d354f39 100644 --- a/api/gen/powergate/user/v1/user_grpc.pb.go +++ b/api/gen/powergate/user/v1/user_grpc.pb.go @@ -27,6 +27,7 @@ type UserServiceClient interface { Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*RemoveResponse, error) // Data Stage(ctx context.Context, opts ...grpc.CallOption) (UserService_StageClient, error) + StageCid(ctx context.Context, in *StageCidRequest, opts ...grpc.CallOption) (*StageCidResponse, error) ReplaceData(ctx context.Context, in *ReplaceDataRequest, opts ...grpc.CallOption) (*ReplaceDataResponse, error) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (UserService_GetClient, error) WatchLogs(ctx context.Context, in *WatchLogsRequest, opts ...grpc.CallOption) (UserService_WatchLogsClient, error) @@ -149,6 +150,15 @@ func (x *userServiceStageClient) CloseAndRecv() (*StageResponse, error) { return m, nil } +func (c *userServiceClient) StageCid(ctx context.Context, in *StageCidRequest, opts ...grpc.CallOption) (*StageCidResponse, error) { + out := new(StageCidResponse) + err := c.cc.Invoke(ctx, "/powergate.user.v1.UserService/StageCid", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *userServiceClient) ReplaceData(ctx context.Context, in *ReplaceDataRequest, opts ...grpc.CallOption) (*ReplaceDataResponse, error) { out := new(ReplaceDataResponse) err := c.cc.Invoke(ctx, "/powergate.user.v1.UserService/ReplaceData", in, out, opts...) @@ -421,6 +431,7 @@ type UserServiceServer interface { Remove(context.Context, *RemoveRequest) (*RemoveResponse, error) // Data Stage(UserService_StageServer) error + StageCid(context.Context, *StageCidRequest) (*StageCidResponse, error) ReplaceData(context.Context, *ReplaceDataRequest) (*ReplaceDataResponse, error) Get(*GetRequest, UserService_GetServer) error WatchLogs(*WatchLogsRequest, UserService_WatchLogsServer) error @@ -473,6 +484,9 @@ func (UnimplementedUserServiceServer) Remove(context.Context, *RemoveRequest) (* func (UnimplementedUserServiceServer) Stage(UserService_StageServer) error { return status.Errorf(codes.Unimplemented, "method Stage not implemented") } +func (UnimplementedUserServiceServer) StageCid(context.Context, *StageCidRequest) (*StageCidResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StageCid not implemented") +} func (UnimplementedUserServiceServer) ReplaceData(context.Context, *ReplaceDataRequest) (*ReplaceDataResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ReplaceData not implemented") } @@ -683,6 +697,24 @@ func (x *userServiceStageServer) Recv() (*StageRequest, error) { return m, nil } +func _UserService_StageCid_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StageCidRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).StageCid(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/powergate.user.v1.UserService/StageCid", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).StageCid(ctx, req.(*StageCidRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _UserService_ReplaceData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ReplaceDataRequest) if err := dec(in); err != nil { @@ -1098,6 +1130,10 @@ var _UserService_serviceDesc = grpc.ServiceDesc{ MethodName: "Remove", Handler: _UserService_Remove_Handler, }, + { + MethodName: "StageCid", + Handler: _UserService_StageCid_Handler, + }, { MethodName: "ReplaceData", Handler: _UserService_ReplaceData_Handler, diff --git a/api/server/admin/hs.go b/api/server/admin/hs.go new file mode 100644 index 000000000..52cbd31e3 --- /dev/null +++ b/api/server/admin/hs.go @@ -0,0 +1,57 @@ +package admin + +import ( + "context" + + adminProto "github.com/textileio/powergate/api/gen/powergate/admin/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// GCStaged runs a unpinning garbage collection and returns the unpinned cids. +func (a *Service) GCStaged(ctx context.Context, req *adminProto.GCStagedRequest) (*adminProto.GCStagedResponse, error) { + cids, err := a.s.GCStaged(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "running FFS GC: %v", err) + } + + cidsStr := make([]string, len(cids)) + for i := range cids { + cidsStr[i] = cids[i].String() + } + + return &adminProto.GCStagedResponse{ + UnpinnedCids: cidsStr, + }, nil +} + +// PinnedCids returns all the pinned cids in Hot-Storage. +func (a *Service) PinnedCids(ctx context.Context, req *adminProto.PinnedCidsRequest) (*adminProto.PinnedCidsResponse, error) { + pcids, err := a.s.PinnedCids(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting pinned cids: %v", err) + } + + res := &adminProto.PinnedCidsResponse{ + Cids: make([]*adminProto.HSPinnedCid, len(pcids)), + } + + for i, pc := range pcids { + hspc := &adminProto.HSPinnedCid{ + Cid: pc.Cid.String(), + Users: make([]*adminProto.HSPinnedCidUser, len(pc.APIIDs)), + } + + for j, up := range pc.APIIDs { + upr := &adminProto.HSPinnedCidUser{ + UserId: up.ID.String(), + Staged: up.Staged, + CreatedAt: up.CreatedAt, + } + hspc.Users[j] = upr + } + res.Cids[i] = hspc + } + + return res, nil +} diff --git a/api/server/server.go b/api/server/server.go index c001056d6..4fde67a61 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -47,6 +47,7 @@ import ( minerModule "github.com/textileio/powergate/index/miner/module" "github.com/textileio/powergate/iplocation/maxmind" "github.com/textileio/powergate/lotus" + "github.com/textileio/powergate/migration" "github.com/textileio/powergate/reputation" txndstr "github.com/textileio/powergate/txndstransform" "github.com/textileio/powergate/util" @@ -122,6 +123,8 @@ type Config struct { FFSDealFinalityTimeout time.Duration FFSMinimumPieceSize uint64 FFSMaxParallelDealPreparing int + FFSGCAutomaticGCInterval time.Duration + FFSGCStageGracePeriod time.Duration SchedMaxParallel int MinerSelector string MinerSelectorParams string @@ -186,7 +189,11 @@ func NewServer(conf Config) (*Server, error) { } } - ds, err := createDatastore(conf) + if err := runMigrations(conf); err != nil { + return nil, fmt.Errorf("running migrations: %s", err) + } + + ds, err := createDatastore(conf, false) if err != nil { return nil, fmt.Errorf("creating datastore: %s", err) } @@ -240,12 +247,12 @@ func NewServer(conf Config) (*Server, error) { return nil, fmt.Errorf("creating miner selector: %s", err) } - l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger")) + l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger_v2")) if conf.Devnet { conf.FFSMinimumPieceSize = 0 } cs := filcold.New(ms, dm, ipfs, chain, l, lsm, conf.FFSMinimumPieceSize, conf.FFSMaxParallelDealPreparing) - hs, err := coreipfs.New(ipfs, l) + hs, err := coreipfs.New(txndstr.Wrap(ds, "ffs/coreipfs"), ipfs, l) if err != nil { return nil, fmt.Errorf("creating coreipfs: %s", err) } @@ -254,7 +261,8 @@ func NewServer(conf Config) (*Server, error) { if ms, ok := ms.(*sr2.MinerSelector); ok { sr2rf = ms.GetReplicationFactor } - sched, err := scheduler.New(txndstr.Wrap(ds, "ffs/scheduler"), l, hs, cs, conf.SchedMaxParallel, conf.FFSDealFinalityTimeout, sr2rf) + gcConfig := scheduler.GCConfig{StageGracePeriod: conf.FFSGCStageGracePeriod, AutoGCInterval: conf.FFSGCAutomaticGCInterval} + sched, err := scheduler.New(txndstr.Wrap(ds, "ffs/scheduler"), l, hs, cs, conf.SchedMaxParallel, conf.FFSDealFinalityTimeout, sr2rf, gcConfig) if err != nil { return nil, fmt.Errorf("creating scheduler: %s", err) } @@ -529,7 +537,7 @@ func (s *Server) Close() { } } -func createDatastore(conf Config) (datastore.TxnDatastore, error) { +func createDatastore(conf Config, longTimeout bool) (datastore.TxnDatastore, error) { if conf.MongoURI != "" { log.Info("Opening Mongo database...") mongoCtx, cancel := context.WithTimeout(context.Background(), time.Second*10) @@ -537,7 +545,11 @@ func createDatastore(conf Config) (datastore.TxnDatastore, error) { if conf.MongoDB == "" { return nil, fmt.Errorf("mongo database name is empty") } - ds, err := mongods.New(mongoCtx, conf.MongoURI, conf.MongoDB) + var opts []mongods.Option + if longTimeout { + opts = []mongods.Option{mongods.WithOpTimeout(time.Hour), mongods.WithTxnTimeout(time.Hour)} + } + ds, err := mongods.New(mongoCtx, conf.MongoURI, conf.MongoDB, opts...) if err != nil { return nil, fmt.Errorf("opening mongo datastore: %s", err) } @@ -629,3 +641,27 @@ func nonCompliantAPIsInterceptor(nonCompliantAPIs []string) grpc.UnaryServerInte return handler(ctx, req) } } + +func runMigrations(conf Config) error { + log.Infof("Ensuring migrations...") + ds, err := createDatastore(conf, true) + if err != nil { + return fmt.Errorf("creating migration datastore: %s", err) + } + defer func() { + if err := ds.Close(); err != nil { + log.Errorf("closing migration datastore: %s", err) + } + }() + + migrations := map[int]migration.Migration{ + 1: migration.V1MultitenancyMigration, + } + m := migration.New(ds, migrations) + if err := m.Ensure(); err != nil { + return fmt.Errorf("running migrations: %s", err) + } + log.Infof("Migrations ensured") + + return nil +} diff --git a/api/server/user/data.go b/api/server/user/data.go index be72d98f0..8bc2049ab 100644 --- a/api/server/user/data.go +++ b/api/server/user/data.go @@ -13,11 +13,12 @@ import ( "google.golang.org/grpc/status" ) -// Stage allows you to temporarily cache data in hot storage in preparation for pushing a cid storage config. +// Stage allows to stage-pin a stream of data in Hot-Storage in preparation for pushing a storage configuration. func (s *Service) Stage(srv userPb.UserService_StageServer) error { - // check that an API instance exists so not just anyone can add data to hot storage - if _, err := s.getInstanceByToken(srv.Context()); err != nil { - return err + // check that an API instance exists so not just anyone can add data to the hot layer + fapi, err := s.getInstanceByToken(srv.Context()) + if err != nil { + return fmt.Errorf("getting user instance: %s", err) } reader, writer := io.Pipe() @@ -29,7 +30,7 @@ func (s *Service) Stage(srv userPb.UserService_StageServer) error { go receiveFile(srv, writer) - c, err := s.hot.Add(srv.Context(), reader) + c, err := s.hot.Stage(srv.Context(), fapi.ID(), reader) if err != nil { return fmt.Errorf("adding data to hot storage: %s", err) } @@ -37,6 +38,27 @@ func (s *Service) Stage(srv userPb.UserService_StageServer) error { return srv.SendAndClose(&userPb.StageResponse{Cid: util.CidToString(c)}) } +// StageCid allows to stage-pin a cid in Hot-Storage in preparation for pushing a storage configuration. +func (s *Service) StageCid(ctx context.Context, req *userPb.StageCidRequest) (*userPb.StageCidResponse, error) { + // check that an API instance exists so not just anyone can add data to the hot layer + fapi, err := s.getInstanceByToken(ctx) + if err != nil { + return nil, fmt.Errorf("getting user instance: %s", err) + } + + c, err := util.CidFromString(req.Cid) + if err != nil { + return nil, fmt.Errorf("parsing cid: %s", err) + } + + err = s.hot.StageCid(ctx, fapi.ID(), c) + if err != nil { + return nil, fmt.Errorf("stage pinning cid in hot-storage: %s", err) + } + + return &userPb.StageCidResponse{}, nil +} + // ReplaceData calls ffs.Replace. func (s *Service) ReplaceData(ctx context.Context, req *userPb.ReplaceDataRequest) (*userPb.ReplaceDataResponse, error) { i, err := s.getInstanceByToken(ctx) diff --git a/cli-docs/pow/pow_admin.md b/cli-docs/pow/pow_admin.md index f80c6daeb..6a66375d2 100644 --- a/cli-docs/pow/pow_admin.md +++ b/cli-docs/pow/pow_admin.md @@ -23,6 +23,7 @@ Provides admin commands ### SEE ALSO * [pow](pow.md) - A client for storage and retreival of powergate data +* [pow admin data](pow_admin_data.md) - Provides admin data commands * [pow admin jobs](pow_admin_jobs.md) - Provides admin jobs commands * [pow admin users](pow_admin_users.md) - Provides admin users commands * [pow admin wallet](pow_admin_wallet.md) - Provides admin wallet commands diff --git a/cli-docs/pow/pow_admin_data.md b/cli-docs/pow/pow_admin_data.md new file mode 100644 index 000000000..8d551e09d --- /dev/null +++ b/cli-docs/pow/pow_admin_data.md @@ -0,0 +1,28 @@ +## pow admin data + +Provides admin data commands + +### Synopsis + +Provides admin data commands + +### Options + +``` + -h, --help help for data +``` + +### Options inherited from parent commands + +``` + --admin-token string admin auth token + --serverAddress string address of the powergate service api (default "127.0.0.1:5002") + -t, --token string user auth token +``` + +### SEE ALSO + +* [pow admin](pow_admin.md) - Provides admin commands +* [pow admin data gcstaged](pow_admin_data_gcstaged.md) - Unpins unused staged data. +* [pow admin data pinnedCids](pow_admin_data_pinnedCids.md) - List pinned cids information in hot-storage. + diff --git a/cli-docs/pow/pow_admin_data_gcstaged.md b/cli-docs/pow/pow_admin_data_gcstaged.md new file mode 100644 index 000000000..be3eb3654 --- /dev/null +++ b/cli-docs/pow/pow_admin_data_gcstaged.md @@ -0,0 +1,30 @@ +## pow admin data gcstaged + +Unpins unused staged data. + +### Synopsis + +Unpins staged data not used by queued or executing jobs. + +``` +pow admin data gcstaged [flags] +``` + +### Options + +``` + -h, --help help for gcstaged +``` + +### Options inherited from parent commands + +``` + --admin-token string admin auth token + --serverAddress string address of the powergate service api (default "127.0.0.1:5002") + -t, --token string user auth token +``` + +### SEE ALSO + +* [pow admin data](pow_admin_data.md) - Provides admin data commands + diff --git a/cli-docs/pow/pow_admin_data_pinnedCids.md b/cli-docs/pow/pow_admin_data_pinnedCids.md new file mode 100644 index 000000000..c1fe67ebb --- /dev/null +++ b/cli-docs/pow/pow_admin_data_pinnedCids.md @@ -0,0 +1,30 @@ +## pow admin data pinnedCids + +List pinned cids information in hot-storage. + +### Synopsis + +List pinned cids information in hot-storage. + +``` +pow admin data pinnedCids [flags] +``` + +### Options + +``` + -h, --help help for pinnedCids +``` + +### Options inherited from parent commands + +``` + --admin-token string admin auth token + --serverAddress string address of the powergate service api (default "127.0.0.1:5002") + -t, --token string user auth token +``` + +### SEE ALSO + +* [pow admin data](pow_admin_data.md) - Provides admin data commands + diff --git a/cmd/pow/cmd/admin.go b/cmd/pow/cmd/admin.go index 453ab6d4f..ba2f089e3 100644 --- a/cmd/pow/cmd/admin.go +++ b/cmd/pow/cmd/admin.go @@ -12,6 +12,7 @@ func init() { adminJobsCmd, adminUsersCmd, adminWalletCmd, + adminDataCmd, ) } @@ -40,3 +41,9 @@ var adminWalletCmd = &cobra.Command{ Short: "Provides admin wallet commands", Long: `Provides admin wallet commands`, } + +var adminDataCmd = &cobra.Command{ + Use: "data", + Short: "Provides admin data commands", + Long: `Provides admin data commands`, +} diff --git a/cmd/pow/cmd/admin_data.go b/cmd/pow/cmd/admin_data.go new file mode 100644 index 000000000..7e2328930 --- /dev/null +++ b/cmd/pow/cmd/admin_data.go @@ -0,0 +1,63 @@ +package cmd + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "google.golang.org/protobuf/encoding/protojson" +) + +func init() { + adminDataCmd.AddCommand( + adminDataGCStaged, + adminDataPinnedCids, + ) +} + +var adminDataGCStaged = &cobra.Command{ + Use: "gcstaged", + Short: "Unpins unused staged data.", + Long: `Unpins staged data not used by queued or executing jobs.`, + Args: cobra.NoArgs, + PreRun: func(cmd *cobra.Command, args []string) { + err := viper.BindPFlags(cmd.Flags()) + checkErr(err) + }, + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), cmdTimeout) + defer cancel() + + res, err := powClient.Admin.Data.GCStaged(adminAuthCtx(ctx)) + checkErr(err) + + json, err := protojson.MarshalOptions{Multiline: true, Indent: " ", EmitUnpopulated: true}.Marshal(res) + checkErr(err) + + fmt.Println(string(json)) + }, +} + +var adminDataPinnedCids = &cobra.Command{ + Use: "pinnedCids", + Short: "List pinned cids information in hot-storage.", + Long: "List pinned cids information in hot-storage.", + Args: cobra.NoArgs, + PreRun: func(cmd *cobra.Command, args []string) { + err := viper.BindPFlags(cmd.Flags()) + checkErr(err) + }, + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), cmdTimeout) + defer cancel() + + res, err := powClient.Admin.Data.PinnedCids(adminAuthCtx(ctx)) + checkErr(err) + + json, err := protojson.MarshalOptions{Multiline: true, Indent: " ", EmitUnpopulated: true}.Marshal(res) + checkErr(err) + + fmt.Println(string(json)) + }, +} diff --git a/cmd/powd/main.go b/cmd/powd/main.go index 9f8e15c87..ac52354f4 100644 --- a/cmd/powd/main.go +++ b/cmd/powd/main.go @@ -130,6 +130,8 @@ func configFromFlags() (server.Config, error) { ffsDealWatchFinalityTimeout := time.Minute * time.Duration(config.GetInt("ffsdealfinalitytimeout")) ffsMinimumPieceSize := config.GetUint64("ffsminimumpiecesize") ffsMaxParallelDealPreparing := config.GetInt("ffsmaxparalleldealpreparing") + ffsGCInterval := time.Minute * time.Duration(config.GetInt("ffsgcinterval")) + ffsGCStagedGracePeriod := time.Minute * time.Duration(config.GetInt("ffsgcstagedgraceperiod")) dealWatchPollDuration := time.Second * time.Duration(config.GetInt("dealwatchpollduration")) askIndexQueryAskTimeout := time.Second * time.Duration(config.GetInt("askindexqueryasktimeout")) askIndexRefreshInterval := time.Minute * time.Duration(config.GetInt("askindexrefreshinterval")) @@ -167,6 +169,8 @@ func configFromFlags() (server.Config, error) { FFSDealFinalityTimeout: ffsDealWatchFinalityTimeout, FFSMinimumPieceSize: ffsMinimumPieceSize, FFSMaxParallelDealPreparing: ffsMaxParallelDealPreparing, + FFSGCAutomaticGCInterval: ffsGCInterval, + FFSGCStageGracePeriod: ffsGCStagedGracePeriod, AutocreateMasterAddr: autocreateMasterAddr, MinerSelector: minerSelector, MinerSelectorParams: minerSelectorParams, @@ -231,6 +235,7 @@ func setupLogging(repoPath string) error { // Top-level "powd", "server", + "migrations", // Indexes & Reputation "index-miner", @@ -264,6 +269,7 @@ func setupLogging(repoPath string) error { "ffs-sched-sjstore", "ffs-sched-rjstore", "ffs-cidlogger", + "ffs-pinstore", // gRPC Services "powergate-service", @@ -350,28 +356,30 @@ func setupFlags() error { pflag.String("repopath", "~/.powergate", "Path of the repository where Powergate state will be saved.") pflag.Bool("devnet", false, "Indicate that will be running on an ephemeral devnet. --repopath will be autocleaned on exit.") pflag.String("ipfsapiaddr", "/ip4/127.0.0.1/tcp/5001", "IPFS API endpoint multiaddress. (Optional, only needed if FFS is used)") - pflag.String("maxminddbfolder", ".", "Path of the folder containing GeoLite2-City.mmdb") + pflag.String("maxminddbfolder", ".", "Path of the folder containing GeoLite2-City.mmdb.") - pflag.String("mongouri", "", "Mongo URI to connect to MongoDB database. (Optional: if empty, will use Badger)") - pflag.String("mongodb", "", "Mongo database name. (if --mongouri is used, is mandatory") + pflag.String("mongouri", "", "Mongo URI to connect to MongoDB database. (Optional: if empty, will use Badger).") + pflag.String("mongodb", "", "Mongo database name. (if --mongouri is used, is mandatory.") pflag.String("ffsadmintoken", "", "FFS admin token for authorized APIs. If empty, the APIs will be open to the public.") pflag.Bool("ffsusemasteraddr", false, "Use the master address as the initial address for all new FFS instances instead of creating a new unique addess for each new FFS instance.") - pflag.String("ffsminerselector", "sr2", "Miner selector to be used by FFS: 'sr2', 'reputation'") - pflag.String("ffsminerselectorparams", "https://raw.githubusercontent.com/filecoin-project/slingshot/master/miners.json", "Miner selector configuration parameter, depends on --ffsminerselector") - pflag.String("ffsminimumpiecesize", "67108864", "Minimum piece size in bytes allowed to be stored in Filecoin") - pflag.String("ffsschedmaxparallel", "1000", "Maximum amount of Jobs executed in parallel") - pflag.String("ffsdealfinalitytimeout", "4320", "Deadline in minutes in which a deal must prove liveness changing status before considered abandoned") - pflag.String("ffsmaxparalleldealpreparing", "2", "Max parallel deal preparing tasks") - pflag.String("dealwatchpollduration", "900", "Poll interval in seconds used by Deals Module watch to detect state changes") - - pflag.String("askindexqueryasktimeout", "15", "Timeout in seconds for a query ask") - pflag.String("askindexrefreshinterval", "360", "Refresh interval measured in minutes") - pflag.Bool("askindexrefreshonstart", false, "If true it will refresh the index on start") - pflag.String("askindexmaxparallel", "3", "Max parallel query ask to execute while updating index") - - pflag.Bool("disableindices", false, "Disable all indices updates, useful to help Lotus syncing process") - pflag.Bool("disablenoncompliantapis", false, "Disable APIs that may not easily comply with US law") + pflag.String("ffsminerselector", "sr2", "Miner selector to be used by FFS: 'sr2', 'reputation'.") + pflag.String("ffsminerselectorparams", "https://raw.githubusercontent.com/filecoin-project/slingshot/master/miners.json", "Miner selector configuration parameter, depends on --ffsminerselector.") + pflag.String("ffsminimumpiecesize", "67108864", "Minimum piece size in bytes allowed to be stored in Filecoin.") + pflag.String("ffsschedmaxparallel", "1000", "Maximum amount of Jobs executed in parallel.") + pflag.String("ffsdealfinalitytimeout", "4320", "Deadline in minutes in which a deal must prove liveness changing status before considered abandoned.") + pflag.String("ffsmaxparalleldealpreparing", "2", "Max parallel deal preparing tasks.") + pflag.String("ffsgcinterval", "60", "Interval in minutes of Hot Storage GC for staged data; zero is never.") + pflag.String("ffsgcstagedgraceperiod", "60", "Duration in minutes where a staged Cid will be considered GCable if scheduled in a Job.") + pflag.String("dealwatchpollduration", "900", "Poll interval in seconds used by Deals Module watch to detect state changes.") + + pflag.String("askindexqueryasktimeout", "15", "Timeout in seconds for a query ask.") + pflag.String("askindexrefreshinterval", "360", "Refresh interval measured in minutes.") + pflag.Bool("askindexrefreshonstart", false, "If true it will refresh the index on start.") + pflag.String("askindexmaxparallel", "3", "Max parallel query ask to execute while updating index.") + + pflag.Bool("disableindices", false, "Disable all indices updates, useful to help Lotus syncing process.") + pflag.Bool("disablenoncompliantapis", false, "Disable APIs that may not easily comply with US law.") pflag.Parse() diff --git a/ffs/api/api.go b/ffs/api/api.go index 947a55c16..4a7b68888 100644 --- a/ffs/api/api.go +++ b/ffs/api/api.go @@ -133,7 +133,7 @@ func (i *API) GetStorageConfigs(cids ...cid.Cid) (map[cid.Cid]ffs.StorageConfig, // Show returns the information about a stored Cid. If no information is available, // since the Cid was never stored, it returns ErrNotFound. func (i *API) Show(cid cid.Cid) (ffs.StorageInfo, error) { - inf, err := i.sched.GetStorageInfo(cid) + inf, err := i.sched.GetStorageInfo(i.cfg.ID, cid) if err == scheduler.ErrNotFound { return inf, ErrNotFound } diff --git a/ffs/api/api_actions.go b/ffs/api/api_actions.go index 58db2fb44..55a1bdd94 100644 --- a/ffs/api/api_actions.go +++ b/ffs/api/api_actions.go @@ -63,7 +63,7 @@ func (i *API) Remove(c cid.Cid) error { if cfgs[c].Hot.Enabled || cfgs[c].Cold.Enabled { return ErrActiveInStorage } - if err := i.sched.Untrack(c); err != nil { + if err := i.sched.Untrack(i.cfg.ID, c); err != nil { return fmt.Errorf("untracking from scheduler: %s", err) } if err := i.is.removeStorageConfig(c); err != nil { diff --git a/ffs/api/api_import.go b/ffs/api/api_import.go index 93fe9bac7..34bf634d6 100644 --- a/ffs/api/api_import.go +++ b/ffs/api/api_import.go @@ -44,6 +44,7 @@ func (i *API) ImportStorage(payloadCid cid.Cid, pieceCid cid.Cid, deals []Import } cinfo := ffs.StorageInfo{ + APIID: i.cfg.ID, JobID: ffs.EmptyJobID, Cid: payloadCid, Created: time.Now(), @@ -57,7 +58,7 @@ func (i *API) ImportStorage(payloadCid cid.Cid, pieceCid cid.Cid, deals []Import }, } - if err := i.sched.ImportStorageInfo(cinfo); err != nil { + if err := i.sched.ImportStorageInfo(i.cfg.ID, cinfo); err != nil { return fmt.Errorf("importing cid info in scheduler: %s", err) } diff --git a/ffs/api/api_logs.go b/ffs/api/api_logs.go index 4d846278f..c46d8be2c 100644 --- a/ffs/api/api_logs.go +++ b/ffs/api/api_logs.go @@ -25,7 +25,7 @@ func (i *API) WatchLogs(ctx context.Context, ch chan<- ffs.LogEntry, c cid.Cid, } if config.history { - lgs, err := i.sched.GetLogsByCid(ctx, c) + lgs, err := i.sched.GetLogsByCid(ctx, i.cfg.ID, c) if err != nil { return fmt.Errorf("getting history logs of %s: %s", c, err) } @@ -40,7 +40,7 @@ func (i *API) WatchLogs(ctx context.Context, ch chan<- ffs.LogEntry, c cid.Cid, close(ichan) }() for le := range ichan { - if c == le.Cid && (config.jid == ffs.EmptyJobID || config.jid == le.Jid) { + if c == le.Cid && le.APIID == i.cfg.ID && (config.jid == ffs.EmptyJobID || config.jid == le.Jid) { ch <- le } } diff --git a/ffs/coreipfs/coreipfs.go b/ffs/coreipfs/coreipfs.go index 6248369bd..82672cf7a 100644 --- a/ffs/coreipfs/coreipfs.go +++ b/ffs/coreipfs/coreipfs.go @@ -2,80 +2,90 @@ package coreipfs import ( "context" + "errors" "fmt" "io" "sync" "time" "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" ipfsfiles "github.com/ipfs/go-ipfs-files" logging "github.com/ipfs/go-log/v2" iface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/ffs/coreipfs/internal/pinstore" + txndstr "github.com/textileio/powergate/txndstransform" ) var ( log = logging.Logger("ffs-coreipfs") + + // ErrUnpinnedCid indicates that the operation failed because + // the provided cid is unpinned. + ErrUnpinnedCid = errors.New("can't unpin an unpinned cid") + // ErrReplaceFromNotPinned indicates that the source cid to be replaced + // isn't pinned. + ErrReplaceFromNotPinned = errors.New("c1 isn't pinned") ) // CoreIpfs is an implementation of HotStorage interface which saves data // into a remote go-ipfs using the HTTP API. type CoreIpfs struct { ipfs iface.CoreAPI - l ffs.JobLogger + ps *pinstore.Store - lock sync.Mutex - pinset map[cid.Cid]struct{} + lock sync.Mutex } var _ ffs.HotStorage = (*CoreIpfs)(nil) // New returns a new CoreIpfs instance. -func New(ipfs iface.CoreAPI, l ffs.JobLogger) (*CoreIpfs, error) { +func New(ds datastore.TxnDatastore, ipfs iface.CoreAPI, l ffs.JobLogger) (*CoreIpfs, error) { + ps, err := pinstore.New(txndstr.Wrap(ds, "pinstore")) + if err != nil { + return nil, fmt.Errorf("loading pinstore: %s", err) + } ci := &CoreIpfs{ ipfs: ipfs, - l: l, - } - ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) - defer cancel() - if err := ci.fillPinsetCache(ctx); err != nil { - return nil, err + ps: ps, } return ci, nil } -// Remove removes a Cid from hot storage. -func (ci *CoreIpfs) Remove(ctx context.Context, c cid.Cid) error { - log.Debugf("removing cid %s", c) - if err := ci.ipfs.Pin().Rm(ctx, path.IpfsPath(c), options.Pin.RmRecursive(true)); err != nil { - return fmt.Errorf("unpinning cid from ipfs node: %s", err) - } - ci.l.Log(ctx, "Cid data was pinned in IPFS node.") - return nil -} - -// IsStored return if a particular Cid is stored. -func (ci *CoreIpfs) IsStored(ctx context.Context, c cid.Cid) (bool, error) { - _, ok := ci.pinset[c] - return ok, nil -} +// Stage adds the data of io.Reader in the storage, and creates a stage-pin on the resulting cid. +func (ci *CoreIpfs) Stage(ctx context.Context, iid ffs.APIID, r io.Reader) (cid.Cid, error) { + ci.lock.Lock() + defer ci.lock.Unlock() -// Add adds an io.Reader data as file in the IPFS node. -func (ci *CoreIpfs) Add(ctx context.Context, r io.Reader) (cid.Cid, error) { - log.Debugf("adding data-stream...") - p, err := ci.ipfs.Unixfs().Add(ctx, ipfsfiles.NewReaderFile(r), options.Unixfs.Pin(false)) + p, err := ci.ipfs.Unixfs().Add(ctx, ipfsfiles.NewReaderFile(r), options.Unixfs.Pin(true)) if err != nil { return cid.Undef, fmt.Errorf("adding data to ipfs: %s", err) } - log.Debugf("data-stream added with cid %s", p.Cid()) + + if err := ci.ps.AddStaged(iid, p.Cid()); err != nil { + return cid.Undef, fmt.Errorf("saving new pin in pinstore: %s", err) + } + return p.Cid(), nil } -// Get retrieves a cid from the IPFS node. +// StageCid stage-pin a Cid. +func (ci *CoreIpfs) StageCid(ctx context.Context, iid ffs.APIID, c cid.Cid) error { + ci.lock.Lock() + defer ci.lock.Unlock() + + if err := ci.ps.AddStaged(iid, c); err != nil { + return fmt.Errorf("saving new pin in pinstore: %s", err) + } + + return nil +} + +// Get retrieves a cid data from the IPFS node. func (ci *CoreIpfs) Get(ctx context.Context, c cid.Cid) (io.Reader, error) { - log.Debugf("getting cid %s", c) n, err := ci.ipfs.Unixfs().Get(ctx, path.IpfsPath(c)) if err != nil { return nil, fmt.Errorf("getting cid %s from ipfs: %s", c, err) @@ -87,53 +97,229 @@ func (ci *CoreIpfs) Get(ctx context.Context, c cid.Cid) (io.Reader, error) { return file, nil } -// Store stores a Cid in the HotStorage. At the IPFS level, it also mark the Cid as pinned. -func (ci *CoreIpfs) Store(ctx context.Context, c cid.Cid) (int, error) { - log.Debugf("fetching and pinning cid %s", c) +// Pin a cid for an APIID. If the cid was already pinned by a stage from APIID, +// the Cid is considered fully-pinned and not a candidate to be unpinned by GCStaged(). +func (ci *CoreIpfs) Pin(ctx context.Context, iid ffs.APIID, c cid.Cid) (int, error) { + ci.lock.Lock() + defer ci.lock.Unlock() + p := path.IpfsPath(c) - if err := ci.ipfs.Pin().Add(ctx, p, options.Pin.Recursive(true)); err != nil { - return 0, fmt.Errorf("pinning cid %s: %s", c, err) + + // If some APIID already pinned this Cid in the underlying go-ipfs node, then + // we don't need to call the Pin API, just count the reference from this APIID. + if !ci.ps.IsPinned(c) { + if err := ci.ipfs.Pin().Add(ctx, p, options.Pin.Recursive(true)); err != nil { + return 0, fmt.Errorf("pinning cid %s: %s", c, err) + } } s, err := ci.ipfs.Object().Stat(ctx, p) if err != nil { return 0, fmt.Errorf("getting stats of cid %s: %s", c, err) } - ci.lock.Lock() - ci.pinset[c] = struct{}{} - ci.lock.Unlock() + + // Count +1 reference to this Cid by APIID. + if err := ci.ps.Add(iid, p.Cid()); err != nil { + return 0, fmt.Errorf("saving new pin in pinstore: %s", err) + } + return s.CumulativeSize, nil } -// Replace replaces a stored Cid with other Cid. -func (ci *CoreIpfs) Replace(ctx context.Context, c1 cid.Cid, c2 cid.Cid) (int, error) { +// Unpin unpins a Cid for an APIID. If the Cid isn't pinned, it returns ErrUnpinnedCid. +func (ci *CoreIpfs) Unpin(ctx context.Context, iid ffs.APIID, c cid.Cid) error { + ci.lock.Lock() + defer ci.lock.Unlock() + + return ci.removeAndUnpinIfApplies(ctx, iid, c) +} + +// Replace moves the pin from c1 to c2. If c2 was already pinned from a stage, +// it's considered fully-pinned and not GCable. +func (ci *CoreIpfs) Replace(ctx context.Context, iid ffs.APIID, c1 cid.Cid, c2 cid.Cid) (int, error) { + ci.lock.Lock() + defer ci.lock.Unlock() + p1 := path.IpfsPath(c1) p2 := path.IpfsPath(c2) - log.Debugf("updating pin from %s to %s", p1, p2) - if err := ci.ipfs.Pin().Update(ctx, p1, p2); err != nil { - return 0, fmt.Errorf("updating pin %s to %s: %s", c1, c2, err) + + c1refcount, _ := ci.ps.RefCount(c1) + c2refcount, _ := ci.ps.RefCount(c2) + + if c1refcount == 0 { + return 0, ErrReplaceFromNotPinned } + + // If c1 has a single reference, which must be from iid... + if c1refcount == 1 { + // If c2 isn't pinned, then we can move the pin so to unpin c1 and pin c2. + if c2refcount == 0 { + if err := ci.ipfs.Pin().Update(ctx, p1, p2); err != nil { + return 0, fmt.Errorf("updating pin %s to %s: %s", c1, c2, err) + } + } else { // If c2 is pinned, then we need to unpin c1 (c2 is already pinned by other iid). + if err := ci.ipfs.Pin().Rm(ctx, path.IpfsPath(c1), options.Pin.RmRecursive(true)); err != nil { + return 0, fmt.Errorf("unpinning cid from ipfs node: %s", err) + } + } + } else if c2refcount == 0 { + // - c1 is pinned by another iid, so we can't unpin it. + // - c2 isn't pinned by anyone, so we should pin it. + if err := ci.ipfs.Pin().Add(ctx, p2, options.Pin.Recursive(true)); err != nil { + return 0, fmt.Errorf("pinning cid %s: %s", c2, err) + } + } + // If none of the if branches applied: + // - c1 is pinned by another iid, so we can't unpin it. + // - c2 is pinned by some other iid, so it's already pinned in the node, no need to do it. + + // In any case of above if, update the ref counts. + if err := ci.ps.Remove(iid, c1); err != nil { + return 0, fmt.Errorf("removing cid in pinstore: %s", err) + } + if err := ci.ps.Add(iid, c2); err != nil { + return 0, fmt.Errorf("adding cid in pinstore: %s", err) + } + stat, err := ci.ipfs.Object().Stat(ctx, p2) if err != nil { return 0, fmt.Errorf("getting stats of cid %s: %s", c2, err) } - ci.lock.Lock() - delete(ci.pinset, c1) - ci.pinset[c2] = struct{}{} - ci.lock.Unlock() return stat.CumulativeSize, nil } -func (ci *CoreIpfs) fillPinsetCache(ctx context.Context) error { - pins, err := ci.ipfs.Pin().Ls(ctx, options.Pin.Ls.Recursive()) +// IsPinned returns true if c is pinned by iid. +func (ci *CoreIpfs) IsPinned(ctx context.Context, iid ffs.APIID, c cid.Cid) (bool, error) { + return ci.ps.IsPinnedBy(iid, c), nil +} + +// GCStaged unpins Cids that are only pinned by Stage() calls and all pins satisfy the filters. +func (ci *CoreIpfs) GCStaged(ctx context.Context, exclude []cid.Cid, olderThan time.Time) ([]cid.Cid, error) { + ci.lock.Lock() + defer ci.lock.Unlock() + + unpinLst, err := ci.getGCCandidates(exclude, olderThan) if err != nil { - return fmt.Errorf("getting pins from IPFS: %s", err) + return nil, fmt.Errorf("getting gc cid candidates: %s", err) } + + for _, c := range unpinLst { + if err := ci.unpinStaged(ctx, c); err != nil { + return nil, fmt.Errorf("unpinning cid from ipfs node: %s", err) + } + } + + return unpinLst, nil +} + +// PinnedCids return detailed information about pinned cids. +func (ci *CoreIpfs) PinnedCids(ctx context.Context) ([]ffs.PinnedCid, error) { ci.lock.Lock() defer ci.lock.Unlock() - ci.pinset = make(map[cid.Cid]struct{}, len(pins)) - for p := range pins { - ci.pinset[p.Path().Cid()] = struct{}{} + + ps, err := ci.ps.GetAll() + if err != nil { + return nil, fmt.Errorf("getting pins from pinstore: %s", err) + } + + res := make([]ffs.PinnedCid, len(ps)) + for i, pc := range ps { + npc := ffs.PinnedCid{ + Cid: pc.Cid, + APIIDs: make([]ffs.APIIDPinnedCid, len(pc.Pins)), + } + for j, upc := range pc.Pins { + npc.APIIDs[j] = ffs.APIIDPinnedCid{ + ID: upc.APIID, + Staged: upc.Staged, + CreatedAt: upc.CreatedAt, + } + } + res[i] = npc + } + + return res, nil +} + +func (ci *CoreIpfs) getGCCandidates(exclude []cid.Cid, olderThan time.Time) ([]cid.Cid, error) { + lst, err := ci.ps.GetAllOnlyStaged() + if err != nil { + return nil, fmt.Errorf("get staged pins: %s", err) + } + + excludeMap := map[cid.Cid]struct{}{} + for _, c := range exclude { + excludeMap[c] = struct{}{} } + + var unpinList []cid.Cid +Loop: + for _, stagedPin := range lst { + // Double check that ref count is consistent. + total, staged := ci.ps.RefCount(stagedPin.Cid) + if total != staged { + return nil, fmt.Errorf("GC candidates are inconsistent") + } + + // Skip Cids that are excluded. + if _, ok := excludeMap[stagedPin.Cid]; ok { + log.Infof("skipping staged cid %s since it's in exclusion list", stagedPin) + continue Loop + } + // A Cid is only safe to GC if all existing stage-pin are older than + // specified parameter. If any iid stage-pined the Cid more recently than olderThan + // we still have to wait a bit more to consider it for GC. + for _, sp := range stagedPin.Pins { + if sp.CreatedAt > olderThan.Unix() { + continue Loop + } + } + + // The Cid only has staged-pins, and all iids that staged it aren't in exclusion list + // plus are older than olderThan ==> Safe to GCed. + unpinList = append(unpinList, stagedPin.Cid) + } + + return unpinList, nil +} + +func (ci *CoreIpfs) removeAndUnpinIfApplies(ctx context.Context, iid ffs.APIID, c cid.Cid) error { + count, _ := ci.ps.RefCount(c) + if count == 0 { + return ErrUnpinnedCid + } + + if count == 1 { + // There aren't more pinnings for this Cid, let's unpin from IPFS. + log.Infof("unpinning cid %s with ref count 0", c) + if err := ci.ipfs.Pin().Rm(ctx, path.IpfsPath(c), options.Pin.RmRecursive(true)); err != nil { + return fmt.Errorf("unpinning cid from ipfs node: %s", err) + } + } + + if err := ci.ps.Remove(iid, c); err != nil { + return fmt.Errorf("removing cid from pinstore: %s", err) + } + + return nil +} + +func (ci *CoreIpfs) unpinStaged(ctx context.Context, c cid.Cid) error { + count, stagedCount := ci.ps.RefCount(c) + + // Just in case, verify that the total number of pins are equal + // to stage-pins. That is, nobody is pinning this Cid apart from Stage() calls. + if count != stagedCount { + return fmt.Errorf("cid %s hasn't only stage-pins, total %d staged %d", c, count, stagedCount) + } + + if err := ci.ipfs.Pin().Rm(ctx, path.IpfsPath(c), options.Pin.RmRecursive(true)); err != nil { + return fmt.Errorf("unpinning cid from ipfs node: %s", err) + } + + if err := ci.ps.RemoveStaged(c); err != nil { + return fmt.Errorf("removing all staged pins for %s: %s", c, err) + } + return nil } diff --git a/ffs/coreipfs/coreipfs_test.go b/ffs/coreipfs/coreipfs_test.go new file mode 100644 index 000000000..7ae2224f7 --- /dev/null +++ b/ffs/coreipfs/coreipfs_test.go @@ -0,0 +1,574 @@ +package coreipfs + +import ( + "bytes" + "context" + "math/rand" + "sort" + "testing" + "time" + + "github.com/ipfs/go-cid" + ipfsfiles "github.com/ipfs/go-ipfs-files" + httpapi "github.com/ipfs/go-ipfs-http-client" + "github.com/ipfs/interface-go-ipfs-core/options" + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + it "github.com/textileio/powergate/ffs/integrationtest" + "github.com/textileio/powergate/ffs/joblogger" + "github.com/textileio/powergate/tests" + txndstr "github.com/textileio/powergate/txndstransform" +) + +func TestStage(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + iid := ffs.NewAPIID() + + c, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsGCable(t, ci, c) + okPinned, err := ci.IsPinned(ctx, iid, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 0, 1) + + // Re-stage and test ref count is stil 1. + c, err = ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + requireRefCount(t, ci, c, 0, 1) +} + +func TestStageCid(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + // Add as if the Powergate client uses the proxy + p, err := ci.ipfs.Unixfs().Add(ctx, ipfsfiles.NewReaderFile(bytes.NewReader(data)), options.Unixfs.Pin(true)) + require.NoError(t, err) + iid := ffs.NewAPIID() + c := p.Cid() + + err = ci.StageCid(ctx, iid, c) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsGCable(t, ci, c) + okPinned, err := ci.IsPinned(ctx, iid, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 0, 1) + + // Re-stage and test ref count is stil 1. + c, err = ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + requireRefCount(t, ci, c, 0, 1) +} + +func TestStagePinStage(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + iid := ffs.NewAPIID() + + // Stage + c, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + requireRefCount(t, ci, c, 0, 1) + + // Pin that Cid. + _, err = ci.Pin(ctx, iid, c) + require.NoError(t, err) + requireRefCount(t, ci, c, 1, 0) + + // Stage again, it shouldn't be GCable. + c2, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + require.Equal(t, c, c2) + it.RequireIpfsPinnedCid(ctx, t, c2, ipfs) + requireCidIsNotGCable(t, ci, c2) + okPinned, err := ci.IsPinned(ctx, iid, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 1, 0) +} + +func TestPinAndRePin(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + iid := ffs.NewAPIID() + + rd := ipfsfiles.NewReaderFile(bytes.NewReader(data)) + p, err := ipfs.Unixfs().Add(ctx, rd, options.Unixfs.Pin(false)) + require.NoError(t, err) + c := p.Cid() + + size, err := ci.Pin(ctx, iid, c) + require.NoError(t, err) + require.Greater(t, size, 0) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsNotGCable(t, ci, c) + okPinned, err := ci.IsPinned(ctx, iid, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 1, 0) + + // Pin again, check that ref count is still 1. + _, err = ci.Pin(ctx, iid, c) + require.NoError(t, err) + requireRefCount(t, ci, c, 1, 0) +} + +func TestUnpin(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + iid := ffs.NewAPIID() + + rd := ipfsfiles.NewReaderFile(bytes.NewReader(data)) + p, err := ipfs.Unixfs().Add(ctx, rd, options.Unixfs.Pin(false)) + require.NoError(t, err) + c := p.Cid() + + // Test unpin an unpinned cid. + err = ci.Unpin(ctx, iid, c) + require.Equal(t, ErrUnpinnedCid, err) + + // Test pin and unpin. + requireRefCount(t, ci, c, 0, 0) + _, err = ci.Pin(ctx, iid, c) + require.NoError(t, err) + + err = ci.Unpin(ctx, iid, c) + require.NoError(t, err) + requireRefCount(t, ci, c, 0, 0) + + // Test unpin an unpinned cid again. + err = ci.Unpin(ctx, iid, c) + require.Equal(t, ErrUnpinnedCid, err) +} + +func TestReplaceThatUnpinAndPin(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + iid := ffs.NewAPIID() + + // Pin c1 + data := it.RandomBytes(r, 1500) + c1, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + _, err = ci.Pin(ctx, iid, c1) + require.NoError(t, err) + requireRefCount(t, ci, c1, 1, 0) + + // Stage c2 + data2 := it.RandomBytes(r, 1500) + c2, err := ci.Stage(ctx, iid, bytes.NewReader(data2)) + require.NoError(t, err) + requireRefCount(t, ci, c2, 0, 1) + + // Replace + size, err := ci.Replace(ctx, iid, c1, c2) + require.NoError(t, err) + require.Greater(t, size, 0) + + // Post checks + it.RequireIpfsUnpinnedCid(ctx, t, c1, ipfs) // c1 unpinned in node. + it.RequireIpfsPinnedCid(ctx, t, c2, ipfs) // c2 pinned in node. + + okPinned, err := ci.IsPinned(ctx, iid, c1) + require.NoError(t, err) + require.False(t, okPinned) // API claims c1 is unpinned. + okPinned, err = ci.IsPinned(ctx, iid, c2) + require.NoError(t, err) + require.True(t, okPinned) // API claims c2 is unpinned. + + requireRefCount(t, ci, c1, 0, 0) // c1 ref count all 0. + requireRefCount(t, ci, c2, 1, 0) // c2 from staged to strong. +} + +func TestReplaceNotUnpinAndPin(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + + // Pin c1 + iid1 := ffs.NewAPIID() + data := it.RandomBytes(r, 1500) + c1, err := ci.Stage(ctx, iid1, bytes.NewReader(data)) + require.NoError(t, err) + _, err = ci.Pin(ctx, iid1, c1) + require.NoError(t, err) + requireRefCount(t, ci, c1, 1, 0) + + // Make another iid pin c1, so can't be unpinned by replace. + iid2 := ffs.NewAPIID() + _, err = ci.Pin(ctx, iid2, c1) + require.NoError(t, err) + requireRefCount(t, ci, c1, 2, 0) + + // Stage data2 + data2 := it.RandomBytes(r, 1500) + c2, err := ci.Stage(ctx, iid1, bytes.NewReader(data2)) + require.NoError(t, err) + requireRefCount(t, ci, c2, 0, 1) + + // Replace + size, err := ci.Replace(ctx, iid1, c1, c2) + require.NoError(t, err) + require.Greater(t, size, 0) + + // Post checks + it.RequireIpfsPinnedCid(ctx, t, c1, ipfs) // c1 still pinned in node, since used by iid2. + it.RequireIpfsPinnedCid(ctx, t, c2, ipfs) // c2 pinned in node. + + okPinned, err := ci.IsPinned(ctx, iid1, c1) + require.NoError(t, err) + require.False(t, okPinned) // API claims c1 unpinned in iid1. + okPinned, err = ci.IsPinned(ctx, iid2, c1) + require.NoError(t, err) + require.True(t, okPinned) // API claims c1 pinned in iid2. + okPinned, err = ci.IsPinned(ctx, iid1, c2) + require.NoError(t, err) + require.True(t, okPinned) // API claims c2 pinned in iid1. + + requireRefCount(t, ci, c1, 1, 0) // from (2, 0) to (1, 0), only iid2. + requireRefCount(t, ci, c2, 1, 0) // c2 strong pin by replace. +} + +func TestReplaceErrors(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + iid := ffs.NewAPIID() + + // Add directly to IPFS node without pinning + data := it.RandomBytes(r, 1500) + rd := ipfsfiles.NewReaderFile(bytes.NewReader(data)) + p, err := ipfs.Unixfs().Add(ctx, rd, options.Unixfs.Pin(false)) + require.NoError(t, err) + c1 := p.Cid() + + // Stage c2 + data2 := it.RandomBytes(r, 1500) + c2, err := ci.Stage(ctx, iid, bytes.NewReader(data2)) + require.NoError(t, err) + requireRefCount(t, ci, c2, 0, 1) + + // Replace + _, err = ci.Replace(ctx, iid, c1, c2) + require.Equal(t, ErrReplaceFromNotPinned, err) + requireRefCount(t, ci, c1, 0, 0) + requireRefCount(t, ci, c2, 0, 1) +} + +// Test pinning a Cid, unpinning it, and Stage it again. +func TestPinUnpinStage(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + iid := ffs.NewAPIID() + + rd := ipfsfiles.NewReaderFile(bytes.NewReader(data)) + p, err := ipfs.Unixfs().Add(ctx, rd, options.Unixfs.Pin(false)) + require.NoError(t, err) + c := p.Cid() + + _, err = ci.Pin(ctx, iid, c) + require.NoError(t, err) + err = ci.Unpin(ctx, iid, c) + require.NoError(t, err) + requireRefCount(t, ci, c, 0, 0) + + // Stage it again and check invariants: + // must be gcable, is pinned, and should have a staged-pin. + c, err = ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsGCable(t, ci, c) + okPinned, err := ci.IsPinned(ctx, iid, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 0, 1) +} + +func TestMultipleStage(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, ipfs := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + + // Stage with iid1. + iid1 := ffs.NewAPIID() + c, err := ci.Stage(ctx, iid1, bytes.NewReader(data)) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsGCable(t, ci, c) + okPinned, err := ci.IsPinned(ctx, iid1, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 0, 1) + + // Stage with iid1. + iid2 := ffs.NewAPIID() + c, err = ci.Stage(ctx, iid2, bytes.NewReader(data)) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsGCable(t, ci, c) + okPinned, err = ci.IsPinned(ctx, iid2, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 0, 2) + + // Stage with iid3. + iid3 := ffs.NewAPIID() + c, err = ci.Stage(ctx, iid3, bytes.NewReader(data)) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, c, ipfs) + requireCidIsGCable(t, ci, c) + okPinned, err = ci.IsPinned(ctx, iid3, c) + require.NoError(t, err) + require.True(t, okPinned) + requireRefCount(t, ci, c, 0, 3) +} + +func TestTwoStageOnePin(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, _ := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + + // Stage with iid1 + iid1 := ffs.NewAPIID() + c, err := ci.Stage(ctx, iid1, bytes.NewReader(data)) + require.NoError(t, err) + require.True(t, c.Defined()) + + // Stage with other iid. + iid2 := ffs.NewAPIID() + c, err = ci.Stage(ctx, iid2, bytes.NewReader(data)) + require.NoError(t, err) + + requireCidIsGCable(t, ci, c) // Can be GCable + + // Pin with iid1 + _, err = ci.Pin(ctx, iid1, c) + require.NoError(t, err) + requireCidIsNotGCable(t, ci, c) // Can't be GCable + requireRefCount(t, ci, c, 1, 1) // One strong and one staged. + + // Now unpin and check. + err = ci.Unpin(ctx, iid1, c) + require.NoError(t, err) + requireCidIsGCable(t, ci, c) // Now is GCable again. + requireRefCount(t, ci, c, 0, 1) // Only iid2 staged. +} + +func TestPinnedCids(t *testing.T) { + t.Parallel() + ctx := context.Background() + r := rand.New(rand.NewSource(22)) + + ci, _ := newCoreIPFS(t) + data := it.RandomBytes(r, 1500) + + // Stage with iid1 + iid1 := ffs.NewAPIID() + c1, err := ci.Stage(ctx, iid1, bytes.NewReader(data)) + require.NoError(t, err) + + // Stage with iid2. + iid2 := ffs.NewAPIID() + _, err = ci.Stage(ctx, iid2, bytes.NewReader(data)) + require.NoError(t, err) + + // Pin with iid1 + _, err = ci.Pin(ctx, iid1, c1) + require.NoError(t, err) + + // Stage another cid with iid3. + data = it.RandomBytes(r, 1500) + iid3 := ffs.NewAPIID() + c2, err := ci.Stage(ctx, iid3, bytes.NewReader(data)) + require.NoError(t, err) + + // Get all and check. + all, err := ci.PinnedCids(ctx) + require.NoError(t, err) + require.Len(t, all, 2) + + // Order the slices so we have predictable results + // for comparing. In position 0 is c2, and 1 is c1. + sort.Slice(all, func(a, b int) bool { + return all[a].Cid.String() < all[b].Cid.String() + }) + + // c2 is staged by iid3. + require.Equal(t, c2, all[0].Cid) + require.Len(t, all[0].APIIDs, 1) + require.Equal(t, iid3, all[0].APIIDs[0].ID) + require.True(t, all[0].APIIDs[0].Staged) + + // c1 is: + // - pinned by iid1 + // - staged by iid2 + require.Equal(t, c1, all[1].Cid) + require.Len(t, all[1].APIIDs, 2) + require.Equal(t, iid1, all[1].APIIDs[0].ID) + require.False(t, all[1].APIIDs[0].Staged) + require.Equal(t, iid2, all[1].APIIDs[1].ID) + require.True(t, all[1].APIIDs[1].Staged) +} + +func TestGCSingleAPIID(t *testing.T) { + t.Parallel() + ctx := context.Background() + iid := ffs.NewAPIID() + + t.Run("Simple", func(t *testing.T) { + ci, ipfs := newCoreIPFS(t) + // # Stage 1 + r := rand.New(rand.NewSource(22)) + data := it.RandomBytes(r, 1500) + c1, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + + // # Stage 1 + data = it.RandomBytes(r, 1500) + c2, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + + gced, err := ci.GCStaged(ctx, nil, time.Now()) + require.NoError(t, err) + require.Len(t, gced, 2) + + it.RequireIpfsUnpinnedCid(ctx, t, c1, ipfs) + it.RequireIpfsUnpinnedCid(ctx, t, c2, ipfs) + + gced, err = ci.GCStaged(ctx, nil, time.Now()) + require.NoError(t, err) + require.Len(t, gced, 0) + }) + + t.Run("Exclusion", func(t *testing.T) { + ci, ipfs := newCoreIPFS(t) + // # Stage 1 + r := rand.New(rand.NewSource(22)) + data := it.RandomBytes(r, 1500) + c1, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + + // # Stage 1 + data = it.RandomBytes(r, 1500) + c2, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + + gced, err := ci.GCStaged(ctx, []cid.Cid{c1}, time.Now()) + require.NoError(t, err) + require.Len(t, gced, 1) + + it.RequireIpfsUnpinnedCid(ctx, t, c2, ipfs) + + gced, err = ci.GCStaged(ctx, nil, time.Now()) + require.NoError(t, err) + require.Len(t, gced, 1) + it.RequireIpfsUnpinnedCid(ctx, t, c1, ipfs) + }) + + t.Run("Very old", func(t *testing.T) { + ci, ipfs := newCoreIPFS(t) + // # Stage 1 + r := rand.New(rand.NewSource(22)) + data := it.RandomBytes(r, 1500) + c1, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + + // # Stage 1 + data = it.RandomBytes(r, 1500) + c2, err := ci.Stage(ctx, iid, bytes.NewReader(data)) + require.NoError(t, err) + + gced, err := ci.GCStaged(ctx, nil, time.Now().Add(-time.Hour)) + require.NoError(t, err) + require.Len(t, gced, 0) + + gced, err = ci.GCStaged(ctx, nil, time.Now()) + require.NoError(t, err) + require.Len(t, gced, 2) + + it.RequireIpfsUnpinnedCid(ctx, t, c1, ipfs) + it.RequireIpfsUnpinnedCid(ctx, t, c2, ipfs) + }) +} + +func requireCidIsGCable(t *testing.T, ci *CoreIpfs, c cid.Cid) { + t.Helper() + require.True(t, isGCable(t, ci, c)) +} + +func requireCidIsNotGCable(t *testing.T, ci *CoreIpfs, c cid.Cid) { + t.Helper() + require.False(t, isGCable(t, ci, c)) +} + +func isGCable(t *testing.T, ci *CoreIpfs, c cid.Cid) bool { + lst, err := ci.getGCCandidates(nil, time.Now()) + require.NoError(t, err) + + for _, cid := range lst { + if cid.Equals(c) { + return true + } + } + return false +} + +func requireRefCount(t *testing.T, ci *CoreIpfs, c cid.Cid, reqStrong, reqStaged int) { + t.Helper() + total, staged := ci.ps.RefCount(c) + strong := total - staged + + require.Equal(t, strong, reqStrong) + require.Equal(t, staged, reqStaged) +} + +func newCoreIPFS(t *testing.T) (*CoreIpfs, *httpapi.HttpApi) { + ds := tests.NewTxMapDatastore() + ipfs, _ := it.CreateIPFS(t) + l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger")) + hl, err := New(ds, ipfs, l) + require.NoError(t, err) + + return hl, ipfs +} diff --git a/ffs/coreipfs/internal/pinstore/pinstore.go b/ffs/coreipfs/internal/pinstore/pinstore.go new file mode 100644 index 000000000..0b13560f0 --- /dev/null +++ b/ffs/coreipfs/internal/pinstore/pinstore.go @@ -0,0 +1,338 @@ +package pinstore + +import ( + "encoding/json" + "fmt" + "sync" + "time" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + logger "github.com/ipfs/go-log/v2" + "github.com/textileio/powergate/ffs" +) + +var ( + pinBaseKey = datastore.NewKey("pins") + log = logger.Logger("ffs-pinstore") +) + +// Store saves information about pinned Cids per APIID. +// It can be understood as the pinset for a set of APIIDs. +// There're two types of pins: stage-pins and full-pins. +// Stage-pins indicate a form of soft-pinning that clients might +// use as an indication of unpinnable Cids by GC processes. +type Store struct { + lock sync.Mutex + ds datastore.TxnDatastore + cache map[cid.Cid]PinnedCid +} + +// PinnedCid contains information about a pinned +// Cid from multiple APIIDs. +type PinnedCid struct { + Cid cid.Cid + Pins []Pin +} + +// Pin describes a pin of a Cid from a APIID. +// The Stage field indicates if the pin is a stage-pin. +type Pin struct { + APIID ffs.APIID + Staged bool + CreatedAt int64 +} + +// New returns a new Store. +func New(ds datastore.TxnDatastore) (*Store, error) { + cache, err := populateCache(ds) + if err != nil { + return nil, fmt.Errorf("populating cache: %s", err) + } + return &Store{ds: ds, cache: cache}, nil +} + +// AddStaged pins a Cid for APIID with a staged-pin. +// If c is already stage-pinned, its stage-pin timestamp will be refreshed. +// If c is already fully-pinned, this call is a noop (full-pin will be kept). +func (s *Store) AddStaged(iid ffs.APIID, c cid.Cid) error { + s.lock.Lock() + defer s.lock.Unlock() + + var r PinnedCid + if cr, ok := s.cache[c]; ok { + r = cr + } else { + r = PinnedCid{Cid: c} + } + + for i, p := range r.Pins { + if p.APIID == iid { + if !p.Staged { + // Looks like the APIID had this Cid + // pinned with Hot Storage, and later + // decided to stage the Cid again. + // Don't mark this Cid as stage-pin since + // that would be wrong; keep the strong pin. + // This Cid isn't GCable. + return nil + } + // If the Cid is pinned because of a stage, + // and is re-staged then simply update its + // CreatedAt, so it will survive longer to a + // GC. + r.Pins[i].CreatedAt = time.Now().Unix() + return s.persist(r) + } + } + + // If the Cid is not present, create it as a staged pin. + p := Pin{ + APIID: iid, + Staged: true, + CreatedAt: time.Now().Unix(), + } + r.Pins = append(r.Pins, p) + + return s.persist(r) +} + +// Add marks c as fully-pinned by iid. +// If c is already stage-pinned, then is switched to fully-pinned. +// If c is already fully-pinned, then only its timestamp gets refreshed. +func (s *Store) Add(iid ffs.APIID, c cid.Cid) error { + s.lock.Lock() + defer s.lock.Unlock() + + var r PinnedCid + if cr, ok := s.cache[c]; ok { + r = cr + } else { + r = PinnedCid{Cid: c} + } + + var p *Pin + for i := range r.Pins { + if r.Pins[i].APIID == iid { + p = &r.Pins[i] + if !p.Staged { + // Log this situation since might be interesting. + log.Warnf("%s re-pinning already pinned %s", iid, c) + } + break + } + } + if p == nil { + r.Pins = append(r.Pins, Pin{}) + p = &r.Pins[len(r.Pins)-1] + } + *p = Pin{ + APIID: iid, + Staged: false, + CreatedAt: time.Now().Unix(), + } + + return s.persist(r) +} + +// RefCount returns two integers (total, staged). +// total is the total number of ref counts for the Cid. +// staged is the total number of ref counts corresponding to +// staged pins. total includes staged, this means that: +// * total >= staged +// * non-staged pins = total - staged. +func (s *Store) RefCount(c cid.Cid) (int, int) { + s.lock.Lock() + defer s.lock.Unlock() + + r, ok := s.cache[c] + if !ok { + return 0, 0 + } + + var stagedPins int + for _, p := range r.Pins { + if p.Staged { + stagedPins++ + } + } + + return len(r.Pins), stagedPins +} + +// IsPinnedBy returns true if the Cid is pinned for APIID. +// Both strong and staged pins are considered. +func (s *Store) IsPinnedBy(iid ffs.APIID, c cid.Cid) bool { + s.lock.Lock() + defer s.lock.Unlock() + + r, ok := s.cache[c] + if !ok { + return false + } + + for _, p := range r.Pins { + if p.APIID == iid { + return true + } + } + return false +} + +// IsPinned returns true if c is pinned by at least +// one APIID. +func (s *Store) IsPinned(c cid.Cid) bool { + s.lock.Lock() + defer s.lock.Unlock() + + _, ok := s.cache[c] + return ok +} + +// Remove unpins c for iid regarding any pin type. +// If c is unpinned for iid, this is a noop. +func (s *Store) Remove(iid ffs.APIID, c cid.Cid) error { + s.lock.Lock() + defer s.lock.Unlock() + + r, ok := s.cache[c] + if !ok { + log.Warnf("%s removing globally unpinned cid %s", iid, c) + return nil + } + + c1idx := -1 + for i, p := range r.Pins { + if p.APIID == iid { + c1idx = i + break + } + } + if c1idx == -1 { + log.Warnf("%s removing unpinned cid %s", iid, c) + return nil + } + r.Pins[c1idx] = r.Pins[len(r.Pins)-1] + r.Pins = r.Pins[:len(r.Pins)-1] + + return s.persist(r) +} + +// RemoveStaged deletes from the pinstore c if all +// existing pins are stage-pins, if not it fails. +// This is a safe method used by GCs to unpin unpinnable cids. +func (s *Store) RemoveStaged(c cid.Cid) error { + s.lock.Lock() + defer s.lock.Unlock() + + pc, ok := s.cache[c] + if !ok { + return fmt.Errorf("c isn't pinned") + } + + for _, p := range pc.Pins { + if !p.Staged { + return fmt.Errorf("all pins should be stage type") + } + } + + if err := s.ds.Delete(makeKey(c)); err != nil { + return fmt.Errorf("deleting from datastore: %s", err) + } + delete(s.cache, c) + + return nil +} + +// GetAll returns all pinned cids. +func (s *Store) GetAll() ([]PinnedCid, error) { + s.lock.Lock() + defer s.lock.Unlock() + + var res []PinnedCid + for _, v := range s.cache { + v1 := PinnedCid{ + Cid: v.Cid, + Pins: make([]Pin, len(v.Pins)), + } + for i, p := range v.Pins { + v1.Pins[i] = p + } + res = append(res, v1) + } + return res, nil +} + +// GetAllOnlyStaged returns all cids that only have stage-pins. +func (s *Store) GetAllOnlyStaged() ([]PinnedCid, error) { + s.lock.Lock() + defer s.lock.Unlock() + + var res []PinnedCid +Loop: + for _, v := range s.cache { + for _, p := range v.Pins { + if !p.Staged { + continue Loop + } + } + + res = append(res, v) + } + return res, nil +} + +// persist persists a PinnedCid in the datastore. +func (s *Store) persist(r PinnedCid) error { + k := makeKey(r.Cid) + + if len(r.Pins) == 0 { + if err := s.ds.Delete(k); err != nil { + return fmt.Errorf("delete from datastore: %s", err) + } + delete(s.cache, r.Cid) + + return nil + } + buf, err := json.Marshal(r) + if err != nil { + return fmt.Errorf("marshaling to datastore: %s", err) + } + if err := s.ds.Put(k, buf); err != nil { + return fmt.Errorf("put in datastore: %s", err) + } + s.cache[r.Cid] = r + + return nil +} + +func populateCache(ds datastore.TxnDatastore) (map[cid.Cid]PinnedCid, error) { + q := query.Query{Prefix: pinBaseKey.String()} + res, err := ds.Query(q) + if err != nil { + return nil, fmt.Errorf("executing query: %s", err) + } + defer func() { + if err := res.Close(); err != nil { + log.Errorf("closing populating cache query: %s", err) + } + }() + + ret := map[cid.Cid]PinnedCid{} + for res := range res.Next() { + if res.Error != nil { + return nil, fmt.Errorf("query item result: %s", err) + } + var pc PinnedCid + if err := json.Unmarshal(res.Value, &pc); err != nil { + return nil, fmt.Errorf("unmarshaling result: %s", err) + } + ret[pc.Cid] = pc + } + return ret, nil +} + +func makeKey(c cid.Cid) datastore.Key { + return pinBaseKey.ChildString(c.String()) +} diff --git a/ffs/integrationtest/config/config_test.go b/ffs/integrationtest/config/config_test.go index eae906ef9..8f0b93507 100644 --- a/ffs/integrationtest/config/config_test.go +++ b/ffs/integrationtest/config/config_test.go @@ -13,6 +13,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/ffs/scheduler" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" @@ -26,7 +27,7 @@ func TestMain(m *testing.M) { func TestSetDefaultStorageConfig(t *testing.T) { t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() config := ffs.StorageConfig{ @@ -58,7 +59,7 @@ func TestEnabledConfigChange(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -83,7 +84,7 @@ func TestEnabledConfigChange(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -109,7 +110,7 @@ func TestEnabledConfigChange(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfsAPI, client, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, client, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -135,7 +136,7 @@ func TestEnabledConfigChange(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfsAPI, client, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, client, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -184,7 +185,7 @@ func TestFilecoinEnableConfig(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -235,7 +236,7 @@ func TestHotTimeoutConfig(t *testing.T) { scheduler.HardcodedHotTimeout = time.Second * 10 t.SkipNow() t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() t.Run("ShortTime", func(t *testing.T) { @@ -253,7 +254,7 @@ func TestDurationConfig(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -274,7 +275,7 @@ func TestDurationConfig(t *testing.T) { func TestGetDefaultStorageConfig(t *testing.T) { t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() defaultConf := fapi.DefaultStorageConfig() diff --git a/ffs/integrationtest/filters/filters_test.go b/ffs/integrationtest/filters/filters_test.go index 13218f393..bd060aeee 100644 --- a/ffs/integrationtest/filters/filters_test.go +++ b/ffs/integrationtest/filters/filters_test.go @@ -13,6 +13,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/ffs/minerselector/fixed" "github.com/textileio/powergate/tests" @@ -28,7 +29,7 @@ func TestMain(m *testing.M) { func TestFilecoinExcludedMiners(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfsAPI, _, fapi, cls := it.NewAPI(t, 2) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 2) defer cls() r := rand.New(rand.NewSource(22)) @@ -51,7 +52,7 @@ func TestFilecoinTrustedMiner(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfsAPI, _, fapi, cls := it.NewAPI(t, 2) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 2) defer cls() r := rand.New(rand.NewSource(22)) @@ -88,7 +89,7 @@ func TestFilecoinCountryFilter(t *testing.T) { } ms := fixed.New(fixedMiners) ds := tests.NewTxMapDatastore() - manager, closeManager := it.NewFFSManager(t, ds, client, addr, ms, ipfs) + manager, closeManager := itmanager.NewFFSManager(t, ds, client, addr, ms, ipfs) defer closeManager() auth, err := manager.Create(context.Background()) require.NoError(t, err) @@ -121,7 +122,7 @@ func TestFilecoinMaxPriceFilter(t *testing.T) { miner := fixed.Miner{Addr: "f01000", EpochPrice: 500000000} ms := fixed.New([]fixed.Miner{miner}) ds := tests.NewTxMapDatastore() - manager, closeManager := it.NewFFSManager(t, ds, client, addr, ms, ipfs) + manager, closeManager := itmanager.NewFFSManager(t, ds, client, addr, ms, ipfs) defer closeManager() auth, err := manager.Create(context.Background()) require.NoError(t, err) diff --git a/ffs/integrationtest/general/cov.pprof b/ffs/integrationtest/general/cov.pprof new file mode 100644 index 000000000..79b28a0b6 --- /dev/null +++ b/ffs/integrationtest/general/cov.pprof @@ -0,0 +1 @@ +mode: atomic diff --git a/ffs/integrationtest/general/general_test.go b/ffs/integrationtest/general/general_test.go index fdd39785b..57ac631cb 100644 --- a/ffs/integrationtest/general/general_test.go +++ b/ffs/integrationtest/general/general_test.go @@ -16,6 +16,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" ) @@ -32,7 +33,7 @@ func TestAdd(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfsAPI, client, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, client, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -52,7 +53,7 @@ func TestAdd(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -73,7 +74,7 @@ func TestGet(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -93,7 +94,7 @@ func TestGet(t *testing.T) { func TestDealConsistency(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() firstID := fapi.ID() @@ -168,7 +169,7 @@ func TestShow(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() @@ -221,8 +222,8 @@ func TestColdInstanceLoad(t *testing.T) { ds := tests.NewTxMapDatastore() ipfs, ipfsMAddr := it.CreateIPFS(t) - addr, client, ms := it.NewDevnet(t, 1, ipfsMAddr) - manager, closeManager := it.NewFFSManager(t, ds, client, addr, ms, ipfs) + addr, client, ms := itmanager.NewDevnet(t, 1, ipfsMAddr) + manager, closeManager := itmanager.NewFFSManager(t, ds, client, addr, ms, ipfs) auth, err := manager.Create(context.Background()) require.NoError(t, err) @@ -248,7 +249,7 @@ func TestColdInstanceLoad(t *testing.T) { closeManager() // Rehydrate things again and check state. - manager, closeManager = it.NewFFSManager(t, ds, client, addr, ms, ipfs) + manager, closeManager = itmanager.NewFFSManager(t, ds, client, addr, ms, ipfs) defer closeManager() fapi, err = manager.GetByAuthToken(auth.Token) require.NoError(t, err) @@ -273,9 +274,9 @@ func TestHighMinimumPieceSize(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { ds := tests.NewTxMapDatastore() ipfs, ipfsMAddr := it.CreateIPFS(t) - addr, client, ms := it.NewDevnet(t, 1, ipfsMAddr) + addr, client, ms := itmanager.NewDevnet(t, 1, ipfsMAddr) // Set MinimumPieceSize to 1GB so to force failing - manager, closeManager := it.NewCustomFFSManager(t, ds, client, addr, ms, ipfs, 1024*1024*1024) + manager, _, closeManager := itmanager.NewCustomFFSManager(t, ds, client, addr, ms, ipfs, 1024*1024*1024) defer closeManager() auth, err := manager.Create(context.Background()) @@ -293,11 +294,45 @@ func TestHighMinimumPieceSize(t *testing.T) { }) } +func TestStageCidUnpinedOnDisabledHotStorage(t *testing.T) { + t.Parallel() + + tests.RunFlaky(t, func(t *tests.FlakyT) { + ctx := context.Background() + ds := tests.NewTxMapDatastore() + ipfs, ipfsMAddr := it.CreateIPFS(t) + addr, client, ms := itmanager.NewDevnet(t, 1, ipfsMAddr) + manager, hs, closeManager := itmanager.NewCustomFFSManager(t, ds, client, addr, ms, ipfs, 0) + defer closeManager() + auth, err := manager.Create(context.Background()) + require.NoError(t, err) + time.Sleep(time.Second * 3) // Wait for funding txn to finish. + + fapi, err := manager.GetByAuthToken(auth.Token) + require.NoError(t, err) + + r := rand.New(rand.NewSource(22)) + + data := it.RandomBytes(r, 1600) + // Simulate staging the data, which Stage-pins it. + cid, err := hs.Stage(ctx, fapi.ID(), bytes.NewReader(data)) + require.NoError(t, err) + it.RequireIpfsPinnedCid(ctx, t, cid, ipfs) + + config := fapi.DefaultStorageConfig().WithHotEnabled(false) + jid, err := fapi.PushStorageConfig(cid, api.WithStorageConfig(config)) + require.NoError(t, err) + it.RequireEventualJobState(t, fapi, jid, ffs.Success) + time.Sleep(time.Second) + it.RequireIpfsUnpinnedCid(ctx, t, cid, ipfs) + }) +} + func TestRemove(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -326,7 +361,7 @@ func TestRemove(t *testing.T) { func TestImport(t *testing.T) { t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() miner := "t01234" diff --git a/ffs/integrationtest/integrationtest.go b/ffs/integrationtest/integrationtest.go index ff58b53c8..c55d270f3 100644 --- a/ffs/integrationtest/integrationtest.go +++ b/ffs/integrationtest/integrationtest.go @@ -4,46 +4,41 @@ import ( "bytes" "context" "fmt" - "math/big" "math/rand" "time" - "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api/apistruct" "github.com/ipfs/go-cid" - "github.com/ipfs/go-datastore" ipfsfiles "github.com/ipfs/go-ipfs-files" httpapi "github.com/ipfs/go-ipfs-http-client" "github.com/ipfs/interface-go-ipfs-core/options" "github.com/stretchr/testify/require" "github.com/textileio/powergate/deals" - dealsModule "github.com/textileio/powergate/deals/module" "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" - "github.com/textileio/powergate/ffs/coreipfs" - "github.com/textileio/powergate/ffs/filcold" - "github.com/textileio/powergate/ffs/joblogger" - "github.com/textileio/powergate/ffs/manager" - "github.com/textileio/powergate/ffs/minerselector/fixed" - "github.com/textileio/powergate/ffs/scheduler" - "github.com/textileio/powergate/filchain" - "github.com/textileio/powergate/lotus" "github.com/textileio/powergate/tests" - txndstr "github.com/textileio/powergate/txndstransform" "github.com/textileio/powergate/util" - walletModule "github.com/textileio/powergate/wallet/module" ) -const ( - iWalletBal int64 = 4000000000000000 -) +// CreateIPFS creates a docker container running IPFS. +func CreateIPFS(t tests.TestingTWithCleanup) (*httpapi.HttpApi, string) { + ipfsDocker, cls := tests.LaunchIPFSDocker(t) + t.Cleanup(cls) + ipfsAddr := util.MustParseAddr("/ip4/127.0.0.1/tcp/" + ipfsDocker.GetPort("5001/tcp")) + ipfs, err := httpapi.NewApi(ipfsAddr) + require.NoError(t, err) + bridgeIP := ipfsDocker.Container.NetworkSettings.Networks["bridge"].IPAddress + ipfsDockerMAddr := fmt.Sprintf("/ip4/%s/tcp/5001", bridgeIP) + + return ipfs, ipfsDockerMAddr +} // RequireIpfsUnpinnedCid checks that a cid is unpinned in the IPFS node. func RequireIpfsUnpinnedCid(ctx context.Context, t require.TestingT, cid cid.Cid, ipfsAPI *httpapi.HttpApi) { - pins, err := ipfsAPI.Pin().Ls(ctx) + pins, err := ipfsAPI.Pin().Ls(ctx, options.Pin.Ls.Recursive()) require.NoError(t, err) for p := range pins { - require.NotEqual(t, cid, p.Path().Cid(), "Cid isn't unpined from IPFS node") + require.NotEqual(t, cid, p.Path().Cid(), "Cid isn't unpinned from IPFS node") } } @@ -76,116 +71,6 @@ func RequireFilStored(ctx context.Context, t require.TestingT, client *apistruct require.NotEmpty(t, offers) } -// NewAPI returns a new set of components for FFS. -func NewAPI(t tests.TestingTWithCleanup, numMiners int) (*httpapi.HttpApi, *apistruct.FullNodeStruct, *api.API, func()) { - ds := tests.NewTxMapDatastore() - ipfs, ipfsMAddr := CreateIPFS(t) - addr, clientBuilder, ms := NewDevnet(t, numMiners, ipfsMAddr) - manager, closeManager := NewFFSManager(t, ds, clientBuilder, addr, ms, ipfs) - auth, err := manager.Create(context.Background()) - require.NoError(t, err) - time.Sleep(time.Second * 3) // Wait for funding txn to finish. - fapi, err := manager.GetByAuthToken(auth.Token) - require.NoError(t, err) - client, cls, err := clientBuilder(context.Background()) - require.NoError(t, err) - return ipfs, client, fapi, func() { - err := fapi.Close() - require.NoError(t, err) - closeManager() - cls() - } -} - -// CreateIPFS creates a docker container running IPFS. -func CreateIPFS(t tests.TestingTWithCleanup) (*httpapi.HttpApi, string) { - ipfsDocker, cls := tests.LaunchIPFSDocker(t) - t.Cleanup(cls) - ipfsAddr := util.MustParseAddr("/ip4/127.0.0.1/tcp/" + ipfsDocker.GetPort("5001/tcp")) - ipfs, err := httpapi.NewApi(ipfsAddr) - require.NoError(t, err) - bridgeIP := ipfsDocker.Container.NetworkSettings.Networks["bridge"].IPAddress - ipfsDockerMAddr := fmt.Sprintf("/ip4/%s/tcp/5001", bridgeIP) - - return ipfs, ipfsDockerMAddr -} - -// NewDevnet creates a localnet. -func NewDevnet(t tests.TestingTWithCleanup, numMiners int, ipfsAddr string) (address.Address, lotus.ClientBuilder, ffs.MinerSelector) { - client, addr, _ := tests.CreateLocalDevnetWithIPFS(t, numMiners, ipfsAddr, false) - addrs := make([]string, numMiners) - for i := 0; i < numMiners; i++ { - addrs[i] = fmt.Sprintf("f0%d", 1000+i) - } - - fixedMiners := make([]fixed.Miner, len(addrs)) - for i, a := range addrs { - fixedMiners[i] = fixed.Miner{Addr: a, Country: "China", EpochPrice: 500000000} - } - ms := fixed.New(fixedMiners) - return addr, client, ms -} - -// NewFFSManager returns a new FFS manager. -func NewFFSManager(t require.TestingT, ds datastore.TxnDatastore, clientBuilder lotus.ClientBuilder, masterAddr address.Address, ms ffs.MinerSelector, ipfsClient *httpapi.HttpApi) (*manager.Manager, func()) { - return NewCustomFFSManager(t, ds, clientBuilder, masterAddr, ms, ipfsClient, 0) -} - -// NewCustomFFSManager returns a new customized FFS manager. -func NewCustomFFSManager(t require.TestingT, ds datastore.TxnDatastore, cb lotus.ClientBuilder, masterAddr address.Address, ms ffs.MinerSelector, ipfsClient *httpapi.HttpApi, minimumPieceSize uint64) (*manager.Manager, func()) { - dm, err := dealsModule.New(txndstr.Wrap(ds, "deals"), cb, util.AvgBlockTime, time.Minute*10) - require.NoError(t, err) - - fchain := filchain.New(cb) - l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger")) - lsm, err := lotus.NewSyncMonitor(cb) - require.NoError(t, err) - cl := filcold.New(ms, dm, ipfsClient, fchain, l, lsm, minimumPieceSize, 1) - hl, err := coreipfs.New(ipfsClient, l) - require.NoError(t, err) - sched, err := scheduler.New(txndstr.Wrap(ds, "ffs/scheduler"), l, hl, cl, 10, time.Minute*10, nil) - require.NoError(t, err) - - wm, err := walletModule.New(cb, masterAddr, *big.NewInt(iWalletBal), false, "") - require.NoError(t, err) - - manager, err := manager.New(ds, wm, dm, sched, false, true) - require.NoError(t, err) - err = manager.SetDefaultStorageConfig(ffs.StorageConfig{ - Hot: ffs.HotConfig{ - Enabled: true, - AllowUnfreeze: false, - Ipfs: ffs.IpfsConfig{ - AddTimeout: 10, - }, - }, - Cold: ffs.ColdConfig{ - Enabled: true, - Filecoin: ffs.FilConfig{ - ExcludedMiners: nil, - DealMinDuration: util.MinDealDuration, - RepFactor: 1, - }, - }, - }) - require.NoError(t, err) - - return manager, func() { - if err := manager.Close(); err != nil { - t.Errorf("closing api: %s", err) - t.FailNow() - } - if err := sched.Close(); err != nil { - t.Errorf("closing scheduler: %s", err) - t.FailNow() - } - if err := l.Close(); err != nil { - t.Errorf("closing joblogger: %s", err) - t.FailNow() - } - } -} - // RequireStorageJobState checks if the current status of a job matches one of the specified statuses. func RequireStorageJobState(t require.TestingT, fapi *api.API, jid ffs.JobID, statuses ...ffs.JobStatus) ffs.StorageJob { job, err := fapi.GetStorageJob(jid) diff --git a/ffs/integrationtest/logger/logger_test.go b/ffs/integrationtest/logger/logger_test.go index 68b3e3cdb..47d8ebf00 100644 --- a/ffs/integrationtest/logger/logger_test.go +++ b/ffs/integrationtest/logger/logger_test.go @@ -12,6 +12,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/util" ) @@ -24,7 +25,7 @@ func TestMain(m *testing.M) { func TestLogHistory(t *testing.T) { t.Parallel() - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -58,7 +59,7 @@ func TestLogHistory(t *testing.T) { func TestCidLogger(t *testing.T) { t.Parallel() t.Run("WithNoFilters", func(t *testing.T) { - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -97,7 +98,7 @@ func TestCidLogger(t *testing.T) { }) t.Run("WithJidFilter", func(t *testing.T) { t.Run("CorrectJid", func(t *testing.T) { - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -135,7 +136,7 @@ func TestCidLogger(t *testing.T) { it.RequireStorageConfig(t, fapi, cid, nil) }) t.Run("IncorrectJid", func(t *testing.T) { - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) diff --git a/ffs/integrationtest/manager/manager.go b/ffs/integrationtest/manager/manager.go new file mode 100644 index 000000000..3d91bc0b0 --- /dev/null +++ b/ffs/integrationtest/manager/manager.go @@ -0,0 +1,133 @@ +package manager + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/ipfs/go-datastore" + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/ffs/api" + "github.com/textileio/powergate/ffs/coreipfs" + "github.com/textileio/powergate/ffs/filcold" + "github.com/textileio/powergate/ffs/joblogger" + "github.com/textileio/powergate/ffs/manager" + "github.com/textileio/powergate/ffs/minerselector/fixed" + "github.com/textileio/powergate/ffs/scheduler" + "github.com/textileio/powergate/filchain" + "github.com/textileio/powergate/lotus" + "github.com/textileio/powergate/tests" + "github.com/textileio/powergate/util" + + httpapi "github.com/ipfs/go-ipfs-http-client" + dealsModule "github.com/textileio/powergate/deals/module" + it "github.com/textileio/powergate/ffs/integrationtest" + txndstr "github.com/textileio/powergate/txndstransform" + walletModule "github.com/textileio/powergate/wallet/module" +) + +const ( + iWalletBal int64 = 4000000000000000 +) + +// NewAPI returns a new set of components for FFS. +func NewAPI(t tests.TestingTWithCleanup, numMiners int) (*httpapi.HttpApi, *apistruct.FullNodeStruct, *api.API, func()) { + ds := tests.NewTxMapDatastore() + ipfs, ipfsMAddr := it.CreateIPFS(t) + addr, clientBuilder, ms := NewDevnet(t, numMiners, ipfsMAddr) + manager, closeManager := NewFFSManager(t, ds, clientBuilder, addr, ms, ipfs) + auth, err := manager.Create(context.Background()) + require.NoError(t, err) + time.Sleep(time.Second * 3) // Wait for funding txn to finish. + fapi, err := manager.GetByAuthToken(auth.Token) + require.NoError(t, err) + client, cls, err := clientBuilder(context.Background()) + require.NoError(t, err) + return ipfs, client, fapi, func() { + err := fapi.Close() + require.NoError(t, err) + closeManager() + cls() + } +} + +// NewDevnet creates a localnet. +func NewDevnet(t tests.TestingTWithCleanup, numMiners int, ipfsAddr string) (address.Address, lotus.ClientBuilder, ffs.MinerSelector) { + client, addr, _ := tests.CreateLocalDevnetWithIPFS(t, numMiners, ipfsAddr, false) + addrs := make([]string, numMiners) + for i := 0; i < numMiners; i++ { + addrs[i] = fmt.Sprintf("f0%d", 1000+i) + } + + fixedMiners := make([]fixed.Miner, len(addrs)) + for i, a := range addrs { + fixedMiners[i] = fixed.Miner{Addr: a, Country: "China", EpochPrice: 500000000} + } + ms := fixed.New(fixedMiners) + return addr, client, ms +} + +// NewFFSManager returns a new FFS manager. +func NewFFSManager(t require.TestingT, ds datastore.TxnDatastore, clientBuilder lotus.ClientBuilder, masterAddr address.Address, ms ffs.MinerSelector, ipfsClient *httpapi.HttpApi) (*manager.Manager, func()) { + mg, _, err := NewCustomFFSManager(t, ds, clientBuilder, masterAddr, ms, ipfsClient, 0) + return mg, err +} + +// NewCustomFFSManager returns a new customized FFS manager. +func NewCustomFFSManager(t require.TestingT, ds datastore.TxnDatastore, cb lotus.ClientBuilder, masterAddr address.Address, ms ffs.MinerSelector, ipfsClient *httpapi.HttpApi, minimumPieceSize uint64) (*manager.Manager, *coreipfs.CoreIpfs, func()) { + dm, err := dealsModule.New(txndstr.Wrap(ds, "deals"), cb, util.AvgBlockTime, time.Minute*10) + require.NoError(t, err) + + fchain := filchain.New(cb) + l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger")) + lsm, err := lotus.NewSyncMonitor(cb) + require.NoError(t, err) + cl := filcold.New(ms, dm, ipfsClient, fchain, l, lsm, minimumPieceSize, 1) + hl, err := coreipfs.New(ds, ipfsClient, l) + require.NoError(t, err) + sched, err := scheduler.New(txndstr.Wrap(ds, "ffs/scheduler"), l, hl, cl, 10, time.Minute*10, nil, scheduler.GCConfig{AutoGCInterval: 0}) + require.NoError(t, err) + + wm, err := walletModule.New(cb, masterAddr, *big.NewInt(iWalletBal), false, "") + require.NoError(t, err) + + manager, err := manager.New(ds, wm, dm, sched, false, true) + require.NoError(t, err) + err = manager.SetDefaultStorageConfig(ffs.StorageConfig{ + Hot: ffs.HotConfig{ + Enabled: true, + AllowUnfreeze: false, + Ipfs: ffs.IpfsConfig{ + AddTimeout: 10, + }, + }, + Cold: ffs.ColdConfig{ + Enabled: true, + Filecoin: ffs.FilConfig{ + ExcludedMiners: nil, + DealMinDuration: util.MinDealDuration, + RepFactor: 1, + }, + }, + }) + require.NoError(t, err) + + return manager, hl, func() { + if err := manager.Close(); err != nil { + t.Errorf("closing api: %s", err) + t.FailNow() + } + if err := sched.Close(); err != nil { + t.Errorf("closing scheduler: %s", err) + t.FailNow() + } + if err := l.Close(); err != nil { + t.Errorf("closing joblogger: %s", err) + t.FailNow() + } + } +} diff --git a/ffs/integrationtest/renew/renew_test.go b/ffs/integrationtest/renew/renew_test.go index 6a9a5cc32..2a15cecf7 100644 --- a/ffs/integrationtest/renew/renew_test.go +++ b/ffs/integrationtest/renew/renew_test.go @@ -11,6 +11,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/util" ) @@ -28,7 +29,7 @@ func TestRenew(t *testing.T) { t.SkipNow() t.Parallel() - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() ra := rand.New(rand.NewSource(22)) diff --git a/ffs/integrationtest/repair/repair_test.go b/ffs/integrationtest/repair/repair_test.go index 8529a119d..4aefdb828 100644 --- a/ffs/integrationtest/repair/repair_test.go +++ b/ffs/integrationtest/repair/repair_test.go @@ -12,6 +12,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/ffs/scheduler" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" @@ -31,7 +32,7 @@ func TestMain(m *testing.M) { func TestRepair(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { scheduler.RepairEvalFrequency = time.Second * 30 - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) diff --git a/ffs/integrationtest/repfactor/repfactor_test.go b/ffs/integrationtest/repfactor/repfactor_test.go index 73d4902de..8106b5963 100644 --- a/ffs/integrationtest/repfactor/repfactor_test.go +++ b/ffs/integrationtest/repfactor/repfactor_test.go @@ -12,6 +12,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" ) @@ -31,7 +32,7 @@ func TestRepFactor(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { r := rand.New(rand.NewSource(22)) - ipfsAPI, _, fapi, cls := it.NewAPI(t, rf) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, rf) defer cls() cid, _ := it.AddRandomFile(t, r, ipfsAPI) config := fapi.DefaultStorageConfig().WithColdFilRepFactor(rf) @@ -52,7 +53,7 @@ func TestRepFactorIncrease(t *testing.T) { t.SkipNow() tests.RunFlaky(t, func(t *tests.FlakyT) { r := rand.New(rand.NewSource(22)) - ipfsAPI, _, fapi, cls := it.NewAPI(t, 2) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 2) defer cls() cid, _ := it.AddRandomFile(t, r, ipfsAPI) jid, err := fapi.PushStorageConfig(cid) @@ -80,7 +81,7 @@ func TestRepFactorIncrease(t *testing.T) { func TestRepFactorDecrease(t *testing.T) { tests.RunFlaky(t, func(t *tests.FlakyT) { r := rand.New(rand.NewSource(22)) - ipfsAPI, _, fapi, cls := it.NewAPI(t, 2) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 2) defer cls() cid, _ := it.AddRandomFile(t, r, ipfsAPI) @@ -109,7 +110,7 @@ func TestRepFactorDecrease(t *testing.T) { func TestRenewWithDecreasedRepFactor(t *testing.T) { // Too flaky for CI. t.SkipNow() - ipfsAPI, _, fapi, cls := it.NewAPI(t, 2) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 2) defer cls() ra := rand.New(rand.NewSource(22)) diff --git a/ffs/integrationtest/replace/replace_test.go b/ffs/integrationtest/replace/replace_test.go index c800265cd..9a4b752c0 100644 --- a/ffs/integrationtest/replace/replace_test.go +++ b/ffs/integrationtest/replace/replace_test.go @@ -12,6 +12,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" ) @@ -25,7 +26,7 @@ func TestMain(m *testing.M) { func TestPushCidReplace(t *testing.T) { t.Parallel() ctx := context.Background() - ipfs, client, fapi, cls := it.NewAPI(t, 1) + ipfs, client, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -65,8 +66,8 @@ func TestDoubleReplace(t *testing.T) { t.Parallel() ds := tests.NewTxMapDatastore() ipfs, ipfsMAddr := it.CreateIPFS(t) - addr, client, ms := it.NewDevnet(t, 1, ipfsMAddr) - m, closeManager := it.NewFFSManager(t, ds, client, addr, ms, ipfs) + addr, client, ms := itmanager.NewDevnet(t, 1, ipfsMAddr) + m, closeManager := itmanager.NewFFSManager(t, ds, client, addr, ms, ipfs) defer closeManager() // This will ask for a new API to the manager, and do a replace. Always the same replace. diff --git a/ffs/integrationtest/retrieval/retrieval_test.go b/ffs/integrationtest/retrieval/retrieval_test.go index fbb2c0a13..7717935f5 100644 --- a/ffs/integrationtest/retrieval/retrieval_test.go +++ b/ffs/integrationtest/retrieval/retrieval_test.go @@ -13,7 +13,7 @@ import ( logging "github.com/ipfs/go-log/v2" mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" - it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" ) @@ -34,7 +34,7 @@ func TestPartialRetrievalFlow(t *testing.T) { t.Parallel() tests.RunFlaky(t, func(t *tests.FlakyT) { ctx := context.Background() - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() _ = ctx _ = fapi diff --git a/ffs/integrationtest/scheduler/scheduler_test.go b/ffs/integrationtest/scheduler/scheduler_test.go index 03f21b5a2..1dca1d982 100644 --- a/ffs/integrationtest/scheduler/scheduler_test.go +++ b/ffs/integrationtest/scheduler/scheduler_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/textileio/powergate/ffs" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" @@ -25,7 +26,7 @@ func TestMain(m *testing.M) { func TestJobCancelation(t *testing.T) { r := rand.New(rand.NewSource(22)) - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() cid, _ := it.AddRandomFile(t, r, ipfsAPI) @@ -46,7 +47,7 @@ func TestJobCancelation(t *testing.T) { func TestParallelExecution(t *testing.T) { t.Parallel() - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) @@ -81,8 +82,8 @@ func TestResumeScheduler(t *testing.T) { ds := tests.NewTxMapDatastore() ipfs, ipfsMAddr := it.CreateIPFS(t) - addr, client, ms := it.NewDevnet(t, 1, ipfsMAddr) - manager, closeManager := it.NewFFSManager(t, ds, client, addr, ms, ipfs) + addr, client, ms := itmanager.NewDevnet(t, 1, ipfsMAddr) + manager, closeManager := itmanager.NewFFSManager(t, ds, client, addr, ms, ipfs) auth, err := manager.Create(context.Background()) require.NoError(t, err) time.Sleep(time.Second * 3) // Wait for funding txn to finish. @@ -99,7 +100,7 @@ func TestResumeScheduler(t *testing.T) { require.NoError(t, err) closeManager() - manager, closeManager = it.NewFFSManager(t, ds2, client, addr, ms, ipfs) + manager, closeManager = itmanager.NewFFSManager(t, ds2, client, addr, ms, ipfs) defer closeManager() fapi, err = manager.GetByAuthToken(auth.Token) // Get same FFS instance again require.NoError(t, err) @@ -107,12 +108,12 @@ func TestResumeScheduler(t *testing.T) { sh, err := fapi.Show(c) require.NoError(t, err) - require.Equal(t, 1, len(sh.Cold.Filecoin.Proposals)) // Check only one deal still exits. + require.Equal(t, 1, len(sh.Cold.Filecoin.Proposals)) // Check only one deal still exists. } func TestFailedJobMessage(t *testing.T) { t.Parallel() - ipfs, _, fapi, cls := it.NewAPI(t, 1) + ipfs, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() r := rand.New(rand.NewSource(22)) diff --git a/ffs/integrationtest/unfreeze/unfreeze_test.go b/ffs/integrationtest/unfreeze/unfreeze_test.go index 88f321141..0cde99e20 100644 --- a/ffs/integrationtest/unfreeze/unfreeze_test.go +++ b/ffs/integrationtest/unfreeze/unfreeze_test.go @@ -14,6 +14,7 @@ import ( "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/ffs/api" it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/ffs/scheduler" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" @@ -29,7 +30,7 @@ func TestUnfreeze(t *testing.T) { t.Parallel() scheduler.HardcodedHotTimeout = time.Second * 10 tests.RunFlaky(t, func(t *tests.FlakyT) { - ipfsAPI, _, fapi, cls := it.NewAPI(t, 1) + ipfsAPI, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() ra := rand.New(rand.NewSource(22)) diff --git a/ffs/integrationtest/wallet/wallet_test.go b/ffs/integrationtest/wallet/wallet_test.go index dc9e0e254..59c015ae7 100644 --- a/ffs/integrationtest/wallet/wallet_test.go +++ b/ffs/integrationtest/wallet/wallet_test.go @@ -11,7 +11,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" "github.com/textileio/powergate/ffs/api" - it "github.com/textileio/powergate/ffs/integrationtest" + itmanager "github.com/textileio/powergate/ffs/integrationtest/manager" "github.com/textileio/powergate/util" ) @@ -27,7 +27,7 @@ func TestMain(m *testing.M) { func TestAddrs(t *testing.T) { t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() addrs := fapi.Addrs() @@ -38,7 +38,7 @@ func TestAddrs(t *testing.T) { func TestNewAddress(t *testing.T) { t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() addr, err := fapi.NewAddr(context.Background(), "my address") @@ -51,7 +51,7 @@ func TestNewAddress(t *testing.T) { func TestNewAddressDefault(t *testing.T) { t.Parallel() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() addr, err := fapi.NewAddr(context.Background(), "my address", api.WithMakeDefault(true)) @@ -64,7 +64,7 @@ func TestNewAddressDefault(t *testing.T) { func TestSendFil(t *testing.T) { t.Parallel() ctx := context.Background() - _, api, fapi, cls := it.NewAPI(t, 1) + _, api, fapi, cls := itmanager.NewAPI(t, 1) defer cls() const amt int64 = 1 @@ -112,7 +112,7 @@ func TestSendFil(t *testing.T) { func TestSignVerifyMessage(t *testing.T) { t.Parallel() ctx := context.Background() - _, _, fapi, cls := it.NewAPI(t, 1) + _, _, fapi, cls := itmanager.NewAPI(t, 1) defer cls() addrs := fapi.Addrs() diff --git a/ffs/interfaces.go b/ffs/interfaces.go index 8f8c4ce0f..d816b32a2 100644 --- a/ffs/interfaces.go +++ b/ffs/interfaces.go @@ -37,27 +37,37 @@ type DealRecordsManager interface { // HotStorage is a fast storage layer for Cid data. type HotStorage interface { - // Add adds io.Reader data ephemerally (not pinned). - Add(context.Context, io.Reader) (cid.Cid, error) + // Stage adds io.Reader and stage-pins it. + Stage(context.Context, APIID, io.Reader) (cid.Cid, error) - // Remove removes a stored Cid. - Remove(context.Context, cid.Cid) error + // StageCid stage-pins a cid. + StageCid(context.Context, APIID, cid.Cid) error + + // Unpin unpins a Cid. + Unpin(context.Context, APIID, cid.Cid) error // Get retrieves a stored Cid data. Get(context.Context, cid.Cid) (io.Reader, error) - // Store stores a Cid. If the data wasn't previously Added, + // Pin pins a Cid. If the data wasn't previously Added, // depending on the implementation it may use internal mechanisms // for pulling the data, e.g: IPFS network - Store(context.Context, cid.Cid) (int, error) + Pin(context.Context, APIID, cid.Cid) (int, error) // Replace replaces a stored Cid with a new one. It's mostly // thought for mutating data doing this efficiently. - Replace(context.Context, cid.Cid, cid.Cid) (int, error) + Replace(context.Context, APIID, cid.Cid, cid.Cid) (int, error) - // IsStore returns true if the Cid is stored, or false + // IsPinned returns true if the Cid is pinned, or false // otherwise. - IsStored(context.Context, cid.Cid) (bool, error) + IsPinned(context.Context, APIID, cid.Cid) (bool, error) + + // GCStaged unpins Cids that are stage-pinned that aren't + // contained in a exclude list, and were pinned before a time. + GCStaged(context.Context, []cid.Cid, time.Time) ([]cid.Cid, error) + + // PinnedCids returns pinned cids information. + PinnedCids(context.Context) ([]PinnedCid, error) } // DealError contains information about a failed deal. @@ -140,3 +150,16 @@ type MinerProposal struct { Addr string EpochPrice uint64 } + +// PinnedCid provides information about a pinned Cid. +type PinnedCid struct { + Cid cid.Cid + APIIDs []APIIDPinnedCid +} + +// APIIDPinnedCid has information about a Cid pinned by a user. +type APIIDPinnedCid struct { + ID APIID + Staged bool + CreatedAt int64 +} diff --git a/ffs/joblogger/joblogger.go b/ffs/joblogger/joblogger.go index ed7f20598..0a67e6f94 100644 --- a/ffs/joblogger/joblogger.go +++ b/ffs/joblogger/joblogger.go @@ -56,10 +56,11 @@ func (cl *Logger) Log(ctx context.Context, format string, a ...interface{}) { c, _ := ctx.Value(ffs.CtxStorageCid).(cid.Cid) rid, _ := ctx.Value(ffs.CtxRetrievalID).(ffs.RetrievalID) jid, _ := ctx.Value(ffs.CtxKeyJid).(ffs.JobID) + iid, _ := ctx.Value(ffs.CtxAPIID).(ffs.APIID) now := time.Now() nowNano := now.UnixNano() - key := makeKey(c, rid, nowNano) + key := makeKey(iid, c, rid, nowNano) le := logEntry{ Cid: c, RetrievalID: rid, @@ -78,6 +79,7 @@ func (cl *Logger) Log(ctx context.Context, format string, a ...interface{}) { } entry := ffs.LogEntry{ + APIID: iid, Cid: le.Cid, Jid: le.Jid, Timestamp: now, @@ -95,8 +97,8 @@ func (cl *Logger) Log(ctx context.Context, format string, a ...interface{}) { } // GetByCid returns history logs for a Cid. -func (cl *Logger) GetByCid(ctx context.Context, c cid.Cid) ([]ffs.LogEntry, error) { - q := query.Query{Prefix: makeCidKey(c).String()} +func (cl *Logger) GetByCid(ctx context.Context, iid ffs.APIID, c cid.Cid) ([]ffs.LogEntry, error) { + q := query.Query{Prefix: makeStorageCidKey(iid, c).String()} res, err := cl.ds.Query(q) if err != nil { return nil, fmt.Errorf("running query: %s", err) @@ -176,21 +178,24 @@ func (cl *Logger) Close() error { return nil } -func makeKey(c cid.Cid, rid ffs.RetrievalID, timestamp int64) datastore.Key { +func makeKey(iid ffs.APIID, c cid.Cid, rid ffs.RetrievalID, timestamp int64) datastore.Key { + if !iid.Valid() { + panic("iid can't be empty") + } strt := strconv.FormatInt(timestamp, 10) if c != cid.Undef { - return makeCidKey(c).ChildString(strt) + return makeStorageCidKey(iid, c).ChildString(strt) } if rid != ffs.EmptyRetrievalID { - return makeRetrievalKey(c).ChildString(strt) + return makeRetrievalKey(iid, c).ChildString(strt) } panic("log should be from stored cid or retrieval request") } -func makeCidKey(c cid.Cid) datastore.Key { - return datastore.NewKey(util.CidToString(c)) +func makeStorageCidKey(iid ffs.APIID, c cid.Cid) datastore.Key { + return datastore.NewKey(iid.String()).ChildString(util.CidToString(c)) } -func makeRetrievalKey(rid cid.Cid) datastore.Key { - return datastore.NewKey(rid.String()) +func makeRetrievalKey(iid ffs.APIID, rid cid.Cid) datastore.Key { + return datastore.NewKey(iid.String()).ChildString(rid.String()) } diff --git a/ffs/scheduler/internal/cistore/cistore.go b/ffs/scheduler/internal/cistore/cistore.go index b48b1e52b..9764bbb77 100644 --- a/ffs/scheduler/internal/cistore/cistore.go +++ b/ffs/scheduler/internal/cistore/cistore.go @@ -30,9 +30,9 @@ func New(ds datastore.Datastore) *Store { } // Get gets the current stored state of a Cid. -func (s *Store) Get(c cid.Cid) (ffs.StorageInfo, error) { +func (s *Store) Get(iid ffs.APIID, c cid.Cid) (ffs.StorageInfo, error) { var ci ffs.StorageInfo - buf, err := s.ds.Get(makeKey(c)) + buf, err := s.ds.Get(makeKey(iid, c)) if err == datastore.ErrNotFound { return ci, ErrNotFound } @@ -47,6 +47,9 @@ func (s *Store) Get(c cid.Cid) (ffs.StorageInfo, error) { // Put saves a new storage state for a Cid. func (s *Store) Put(ci ffs.StorageInfo) error { + if !ci.APIID.Valid() { + return fmt.Errorf("instance id is invalid") + } if !ci.Cid.Defined() { return fmt.Errorf("cid can't be undefined") } @@ -54,12 +57,12 @@ func (s *Store) Put(ci ffs.StorageInfo) error { if err != nil { return fmt.Errorf("marshaling cid info for datastore: %s", err) } - if err := s.ds.Put(makeKey(ci.Cid), buf); err != nil { + if err := s.ds.Put(makeKey(ci.APIID, ci.Cid), buf); err != nil { return fmt.Errorf("put cid info in datastore: %s", err) } return nil } -func makeKey(c cid.Cid) datastore.Key { - return datastore.NewKey(util.CidToString(c)) +func makeKey(iid ffs.APIID, c cid.Cid) datastore.Key { + return datastore.NewKey(iid.String()).ChildString(util.CidToString(c)) } diff --git a/ffs/scheduler/internal/sjstore/sjstore.go b/ffs/scheduler/internal/sjstore/sjstore.go index c65dc1ec2..813423ac1 100644 --- a/ffs/scheduler/internal/sjstore/sjstore.go +++ b/ffs/scheduler/internal/sjstore/sjstore.go @@ -24,7 +24,7 @@ var ( ErrNotFound = errors.New("job not found") dsBaseJob = datastore.NewKey("job") - dsBaseStartedDeals = datastore.NewKey("starteddeals") + dsBaseStartedDeals = datastore.NewKey("starteddeals_v2") ) // Store is a Datastore implementation of JobStore, which saves @@ -34,8 +34,7 @@ type Store struct { ds datastore.Datastore watchers []watcher - queued []ffs.StorageJob - executingCids map[cid.Cid]ffs.JobID + queued []ffs.StorageJob jobStatusCache map[ffs.APIID]map[cid.Cid]map[cid.Cid]deals.StorageDealInfo @@ -60,7 +59,6 @@ type watcher struct { func New(ds datastore.Datastore) (*Store, error) { s := &Store{ ds: ds, - executingCids: make(map[cid.Cid]ffs.JobID), jobStatusCache: make(map[ffs.APIID]map[cid.Cid]map[cid.Cid]deals.StorageDealInfo), queuedJobs: make(map[ffs.APIID]map[cid.Cid][]*ffs.StorageJob), executingJobs: make(map[ffs.APIID]map[cid.Cid]*ffs.StorageJob), @@ -151,7 +149,7 @@ func (s *Store) Dequeue() (*ffs.StorageJob, error) { defer s.lock.Unlock() for _, job := range s.queued { - execJobID, ok := s.executingCids[job.Cid] + execJob, ok := s.executingJobs[job.APIID][job.Cid] if job.Status == ffs.Queued && !ok { job.Status = ffs.Executing if err := s.put(job); err != nil { @@ -159,7 +157,7 @@ func (s *Store) Dequeue() (*ffs.StorageJob, error) { } return &job, nil } - log.Infof("queued %s is delayed since job %s is running", job.ID, execJobID) + log.Infof("queued %s is delayed since job %s is running", job.ID, execJob.ID) } return nil, nil } @@ -181,22 +179,26 @@ func (s *Store) Enqueue(j ffs.StorageJob) error { } // GetExecutingJob returns a JobID that is currently executing for -// data with cid c. If there's not such job, it returns nil. -func (s *Store) GetExecutingJob(c cid.Cid) *ffs.JobID { - j, ok := s.executingCids[c] +// data with cid c in iid. If there's not such job, it returns nil. +func (s *Store) GetExecutingJob(iid ffs.APIID, c cid.Cid) *ffs.JobID { + j, ok := s.executingJobs[iid][c] if !ok { return nil } - return &j + return &j.ID } // GetStats return the current Stats for storage jobs. func (s *Store) GetStats() Stats { s.lock.Lock() defer s.lock.Unlock() + var count int + for _, iidJobs := range s.executingJobs { + count += len(iidJobs) + } return Stats{ TotalQueued: len(s.queued), - TotalExecuting: len(s.executingCids), + TotalExecuting: count, } } @@ -204,11 +206,11 @@ func (s *Store) GetStats() Stats { func (s *Store) GetExecutingJobIDs() []ffs.JobID { s.lock.Lock() defer s.lock.Unlock() - res := make([]ffs.JobID, len(s.executingCids)) - var i int - for _, jid := range s.executingCids { - res[i] = jid - i++ + var res []ffs.JobID + for _, iid := range s.executingJobs { + for _, j := range iid { + res = append(res, j.ID) + } } return res } @@ -221,7 +223,7 @@ func (s *Store) cancelQueued(c cid.Cid) error { } defer func() { if err := res.Close(); err != nil { - log.Errorf("closing getbystatus query result: %s", err) + log.Errorf("closing cancelQueued query result: %s", err) } }() for r := range res.Next() { @@ -292,7 +294,7 @@ type StartedDeals struct { // AddStartedDeals is a temporal storage solution of deals that are started // are being watched. It serves as a recovery point to reattach to fired // deals when the scheduler was abruptly interrupted. -func (s *Store) AddStartedDeals(c cid.Cid, proposals []cid.Cid) error { +func (s *Store) AddStartedDeals(iid ffs.APIID, c cid.Cid, proposals []cid.Cid) error { s.lock.Lock() defer s.lock.Unlock() sd := StartedDeals{Cid: c, ProposalCids: proposals} @@ -300,35 +302,36 @@ func (s *Store) AddStartedDeals(c cid.Cid, proposals []cid.Cid) error { if err != nil { return fmt.Errorf("marshaling started deals: %s", err) } - if err := s.ds.Put(makeStartedDealsKey(c), buf); err != nil { + if err := s.ds.Put(makeStartedDealsKey(iid, c), buf); err != nil { return fmt.Errorf("saving started deals to datastore: %s", err) } return nil } // RemoveStartedDeals removes all started deals from Cid. -func (s *Store) RemoveStartedDeals(c cid.Cid) error { +func (s *Store) RemoveStartedDeals(iid ffs.APIID, c cid.Cid) error { s.lock.Lock() defer s.lock.Unlock() - if err := s.ds.Delete(makeStartedDealsKey(c)); err != nil { + if err := s.ds.Delete(makeStartedDealsKey(iid, c)); err != nil { return fmt.Errorf("deleting started deals from datastore: %s", err) } return nil } -// GetStartedDeals gets all stored started deals from Cid. If no started -// deals are present, an empty slice is returned. -func (s *Store) GetStartedDeals(c cid.Cid) ([]cid.Cid, error) { +// GetStartedDeals gets all stored started deals from Cid for an APIID. +// If no started deals are present, an empty slice is returned. +func (s *Store) GetStartedDeals(iid ffs.APIID, c cid.Cid) ([]cid.Cid, error) { s.lock.Lock() defer s.lock.Unlock() - var sd StartedDeals - b, err := s.ds.Get(makeStartedDealsKey(c)) + + b, err := s.ds.Get(makeStartedDealsKey(iid, c)) if err == datastore.ErrNotFound { return nil, nil } if err != nil { return nil, fmt.Errorf("getting started deals from datastore: %s", err) } + var sd StartedDeals if err := json.Unmarshal(b, &sd); err != nil { return nil, fmt.Errorf("unmarshaling started deals from datastore: %s", err) } @@ -458,16 +461,8 @@ func (s *Store) put(j ffs.StorageJob) error { // Update executing cids cache. ensureJobsMap(s.executingJobs, j.APIID) if j.Status == ffs.Executing { - s.executingCids[j.Cid] = j.ID s.executingJobs[j.APIID][j.Cid] = &j } else { - execJobID, ok := s.executingCids[j.Cid] - // If the executing job is not longer executing, - // take out from executing cache. - if ok && execJobID == j.ID { - delete(s.executingCids, j.Cid) - } - execJob, ok := s.executingJobs[j.APIID][j.Cid] if ok && execJob.ID == j.ID { delete(s.executingJobs[j.APIID], j.Cid) @@ -578,7 +573,6 @@ func (s *Store) loadCaches() error { ensureJobsSliceMap(s.queuedJobs, j.APIID) s.queuedJobs[j.APIID][j.Cid] = append(s.queuedJobs[j.APIID][j.Cid], &j) } else if j.Status == ffs.Executing { - s.executingCids[j.Cid] = j.ID ensureJobsMap(s.executingJobs, j.APIID) s.executingJobs[j.APIID][j.Cid] = &j } @@ -630,8 +624,8 @@ func isSuccessful(j ffs.StorageJob) bool { return j.Status == ffs.Success } -func makeStartedDealsKey(c cid.Cid) datastore.Key { - return dsBaseStartedDeals.ChildString(util.CidToString(c)) +func makeStartedDealsKey(iid ffs.APIID, c cid.Cid) datastore.Key { + return dsBaseStartedDeals.ChildString(iid.String()).ChildString(util.CidToString(c)) } func makeKey(jid ffs.JobID) datastore.Key { diff --git a/ffs/scheduler/internal/sjstore/sjstore_test.go b/ffs/scheduler/internal/sjstore/sjstore_test.go index 68e1ed3c5..2b314c24d 100644 --- a/ffs/scheduler/internal/sjstore/sjstore_test.go +++ b/ffs/scheduler/internal/sjstore/sjstore_test.go @@ -104,10 +104,11 @@ func TestStartedDeals(t *testing.T) { t.Parallel() s := create(t) + iid := ffs.NewAPIID() b, _ := multihash.Encode([]byte("data"), multihash.SHA1) cidData := cid.NewCidV1(1, b) - fds, err := s.GetStartedDeals(cidData) + fds, err := s.GetStartedDeals(iid, cidData) require.NoError(t, err) require.Equal(t, 0, len(fds)) @@ -117,17 +118,17 @@ func TestStartedDeals(t *testing.T) { cidProp2 := cid.NewCidV1(1, b) startedDeals := []cid.Cid{cidProp1, cidProp2} - err = s.AddStartedDeals(cidData, startedDeals) + err = s.AddStartedDeals(iid, cidData, startedDeals) require.NoError(t, err) - fds, err = s.GetStartedDeals(cidData) + fds, err = s.GetStartedDeals(iid, cidData) require.NoError(t, err) require.Equal(t, startedDeals, fds) - err = s.RemoveStartedDeals(cidData) + err = s.RemoveStartedDeals(iid, cidData) require.NoError(t, err) - fds, err = s.GetStartedDeals(cidData) + fds, err = s.GetStartedDeals(iid, cidData) require.NoError(t, err) require.Equal(t, 0, len(fds)) } diff --git a/ffs/scheduler/internal/trackstore/trackstore.go b/ffs/scheduler/internal/trackstore/trackstore.go index a4168624b..68e789d19 100644 --- a/ffs/scheduler/internal/trackstore/trackstore.go +++ b/ffs/scheduler/internal/trackstore/trackstore.go @@ -18,41 +18,26 @@ import ( // This store is used by the Scheduler background jobs that // repair or renew storage configurations. type Store struct { - lock sync.Mutex - ds datastore.Datastore - repairables map[cid.Cid]struct{} - renewables map[cid.Cid]struct{} + lock sync.Mutex + ds datastore.Datastore } -type trackedStorageConfig struct { +// TrackedStorageConfig has information about a StorageConfig from +// an APIID which is repairable/renewable. +type TrackedStorageConfig struct { IID ffs.APIID StorageConfig ffs.StorageConfig } -// New retruns a new Store. -func New(ds datastore.Datastore) (*Store, error) { - s := &Store{ - ds: ds, - repairables: map[cid.Cid]struct{}{}, - renewables: map[cid.Cid]struct{}{}, - } - if err := s.loadCaches(); err != nil { - return nil, fmt.Errorf("loading renewable/repairable caches: %s", err) - } - return s, nil +// TrackedCid contains tracked storage configs for a Cid. +type TrackedCid struct { + Cid cid.Cid + Tracked []TrackedStorageConfig } -// Get returns the storage config of a repairable/renewable stored Cid. -func (s *Store) Get(c cid.Cid) (ffs.StorageConfig, ffs.APIID, error) { - v, err := s.ds.Get(datastore.NewKey(c.String())) - if err != nil { - return ffs.StorageConfig{}, "", fmt.Errorf("getting storage config: %s", err) - } - var tsc trackedStorageConfig - if err := json.Unmarshal(v, &tsc); err != nil { - return ffs.StorageConfig{}, "", fmt.Errorf("unmarshaling storage config: %s", err) - } - return tsc.StorageConfig, tsc.IID, nil +// New retruns a new Store. +func New(ds datastore.Datastore) (*Store, error) { + return &Store{ds: ds}, nil } // Put updates the StorageConfig tracking state for a Cid. @@ -65,108 +50,163 @@ func (s *Store) Put(iid ffs.APIID, c cid.Cid, sc ffs.StorageConfig) error { s.lock.Lock() defer s.lock.Unlock() + scs, err := s.get(c) + if err != nil { + return fmt.Errorf("getting current storage configs for cid: %s", err) + } + idx := -1 + for i := range scs { + if scs[i].IID == iid { + idx = i + break + } + } + isRepairable := sc.Repairable isRenewable := sc.Cold.Enabled && sc.Cold.Filecoin.Renew.Enabled - - key := datastore.NewKey(c.String()) + // If has any of the interesting features, it should be in the slice. if isRepairable || isRenewable { - if isRepairable { - s.repairables[c] = struct{}{} - } - if isRenewable { - s.renewables[c] = struct{}{} + if idx == -1 { + nsc := TrackedStorageConfig{IID: iid, StorageConfig: sc} + scs = append(scs, nsc) + } else { + scs[idx].StorageConfig = sc } - tsc := trackedStorageConfig{IID: iid, StorageConfig: sc} - buf, err := json.Marshal(tsc) - if err != nil { - return fmt.Errorf("marshaling storage config: %s", err) - } - if err := s.ds.Put(key, buf); err != nil { - return fmt.Errorf("putting renewable/repairable storageconfig: %s", err) + } else { // Not interesting storage config to track, remove if present or simply return. + if idx != -1 { + scs[idx] = scs[len(scs)-1] + scs = scs[:len(scs)-1] + } else { + return nil } - return nil } - // The provided Storage Config isn't interesting to - // be tracked for renewal or repair. - // Check if we were tracking it before, and if that's the case - // remove it. - _, okRenewable := s.renewables[c] - _, okRepairable := s.repairables[c] - if okRenewable || okRepairable { - if err := s.ds.Delete(key); err != nil { - return fmt.Errorf("deleting disabled storage config: %s", err) - } + if err := s.persist(c, scs); err != nil { + return fmt.Errorf("persisting updated storage configs for cid: %s", err) } + return nil } -// Remove removes a Cid from the store, usually meaning -// the Cid storage config shouldn't be tracked for repair or -// renewal anymore. -func (s *Store) Remove(c cid.Cid) error { - if err := s.ds.Delete(datastore.NewKey(c.String())); err != nil { - return fmt.Errorf("deleting a tracked storage config: %s", err) +// Remove removes tracking the storage config from iid. +func (s *Store) Remove(iid ffs.APIID, c cid.Cid) error { + scs, err := s.get(c) + if err != nil { + return fmt.Errorf("getting current storage configs for cid: %s", err) + } + idx := -1 + for i := range scs { + if scs[i].IID == iid { + idx = i + break + } + } + if idx != -1 { + scs[idx] = scs[len(scs)-1] + scs = scs[:len(scs)-1] + } + if err := s.persist(c, scs); err != nil { + return fmt.Errorf("persisting updated storage configs for cid: %s", err) } - delete(s.renewables, c) - delete(s.repairables, c) - return nil } -// GetRepairables returns the list of Cids which -// have a repairable Storage Config. -func (s *Store) GetRepairables() ([]cid.Cid, error) { +// GetRepairables returns all the tracked repairable storage configs. +func (s *Store) GetRepairables() ([]TrackedCid, error) { s.lock.Lock() defer s.lock.Unlock() - res := make([]cid.Cid, len(s.repairables)) - i := 0 - for k := range s.repairables { - res[i] = k - i++ + tcs, err := s.query(false, true) + if err != nil { + return nil, fmt.Errorf("getting repairable cids from datastore: %s", err) } - return res, nil + + return tcs, nil } -// GetRenewables returns the list of Cids which -// have a renewable Storage Config. -func (s *Store) GetRenewables() ([]cid.Cid, error) { +// GetRenewables returns all the tracked renewable storage configs. +func (s *Store) GetRenewables() ([]TrackedCid, error) { s.lock.Lock() defer s.lock.Unlock() - res := make([]cid.Cid, len(s.renewables)) - i := 0 - for k := range s.renewables { - res[i] = k - i++ + tcs, err := s.query(true, false) + if err != nil { + return nil, fmt.Errorf("getting renewable cids from datastore: %s", err) } - return res, nil + + return tcs, nil } -func (s *Store) loadCaches() error { +func (s *Store) query(renewable bool, repairable bool) ([]TrackedCid, error) { q := query.Query{} r, err := s.ds.Query(q) if err != nil { - return fmt.Errorf("querying persisted tracked storage configs: %s", err) + return nil, fmt.Errorf("querying persisted tracked storage configs: %s", err) } defer func() { _ = r.Close() }() + + var res []TrackedCid for v := range r.Next() { - var tsc trackedStorageConfig - if err := json.Unmarshal(v.Value, &tsc); err != nil { - return fmt.Errorf("unmarshaling storageconfig: %s", err) + if v.Error != nil { + return nil, fmt.Errorf("iterating query result: %s", v.Error) + } + var tscs []TrackedStorageConfig + if err := json.Unmarshal(v.Value, &tscs); err != nil { + return nil, fmt.Errorf("unmarshaling storage configs: %s", err) } cidStr := strings.TrimPrefix(v.Key, "/") c, err := cid.Decode(cidStr) if err != nil { - return fmt.Errorf("decoding cid: %s", err) + return nil, fmt.Errorf("decoding cid: %s", err) + } + + tc := TrackedCid{Cid: c} + for _, tsc := range tscs { + isRepairable := tsc.StorageConfig.Repairable + isRenewable := tsc.StorageConfig.Cold.Enabled && tsc.StorageConfig.Cold.Filecoin.Renew.Enabled + if (repairable && isRepairable) || (renewable && isRenewable) { + tc.Tracked = append(tc.Tracked, tsc) + } } - if tsc.StorageConfig.Repairable { - s.repairables[c] = struct{}{} + if len(tc.Tracked) > 0 { + res = append(res, tc) } - if tsc.StorageConfig.Cold.Enabled && tsc.StorageConfig.Cold.Filecoin.Renew.Enabled { - s.renewables[c] = struct{}{} + } + return res, nil +} + +func (s *Store) persist(c cid.Cid, scs []TrackedStorageConfig) error { + // If the list of storage configs resulted to be empty, then remove it from datastore. + key := datastore.NewKey(c.String()) + if len(scs) == 0 { + if err := s.ds.Delete(key); err != nil { + return fmt.Errorf("deleting empty storage configs for cid: %s", err) } + return nil + } + + // Persist the updated storage config list for the cid. + buf, err := json.Marshal(scs) + if err != nil { + return fmt.Errorf("marshaling storage configs: %s", err) + } + if err := s.ds.Put(key, buf); err != nil { + return fmt.Errorf("saving storage config list in datastore: %s", err) } return nil } + +func (s *Store) get(c cid.Cid) ([]TrackedStorageConfig, error) { + v, err := s.ds.Get(datastore.NewKey(c.String())) + if err == datastore.ErrNotFound { + return nil, nil + } + if err != nil { + return nil, fmt.Errorf("getting tracked storage configs: %s", err) + } + var tsc []TrackedStorageConfig + if err := json.Unmarshal(v, &tsc); err != nil { + return nil, fmt.Errorf("unmarshaling tracked storage configs: %s", err) + } + return tsc, nil +} diff --git a/ffs/scheduler/internal/trackstore/trackstore_test.go b/ffs/scheduler/internal/trackstore/trackstore_test.go index 549bdfa03..8370d45da 100644 --- a/ffs/scheduler/internal/trackstore/trackstore_test.go +++ b/ffs/scheduler/internal/trackstore/trackstore_test.go @@ -1,33 +1,21 @@ package trackstore import ( + "sort" "testing" + "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" "github.com/textileio/powergate/ffs" "github.com/textileio/powergate/tests" "github.com/textileio/powergate/util" ) -func TestAll(t *testing.T) { - ts := create(t) - - // Repairable - c1, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u") - _, _, err := ts.Get(c1) - require.Error(t, err) - - iid1 := ffs.NewAPIID() - scRepairable := ffs.StorageConfig{ +var ( + scRepairable = ffs.StorageConfig{ Repairable: true, } - err = ts.Put(iid1, c1, scRepairable) - require.NoError(t, err) - - // Renewable - c2, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8r") - iid2 := ffs.NewAPIID() - scRenewable := ffs.StorageConfig{ + scRenewable = ffs.StorageConfig{ Cold: ffs.ColdConfig{ Enabled: true, Filecoin: ffs.FilConfig{ @@ -37,42 +25,286 @@ func TestAll(t *testing.T) { }, }, } + scRepairableRenewable = ffs.StorageConfig{ + Repairable: true, + Cold: ffs.ColdConfig{ + Enabled: true, + Filecoin: ffs.FilConfig{ + Renew: ffs.FilRenew{ + Enabled: true, + }, + }, + }, + } +) + +func TestEmpty(t *testing.T) { + t.Parallel() + ts := create(t) + + repairables, err := ts.GetRepairables() + require.NoError(t, err) + require.Len(t, repairables, 0) + + renewables, err := ts.GetRenewables() + require.NoError(t, err) + require.Len(t, renewables, 0) +} + +func TestPut(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + // Repairable + c1, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c1, scRepairable) + require.NoError(t, err) + + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid}}) + + // Renewable + c2, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs82") + err = ts.Put(iid, c2, scRenewable) + require.NoError(t, err) + requireRenewables(t, ts, expected{Cid: c2, IIDs: []ffs.APIID{iid}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid}}) +} + +func TestDoublePut(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c, scRepairable) + require.NoError(t, err) + err = ts.Put(iid, c, scRepairable) + require.NoError(t, err) + + requireRepairables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) +} + +func TestUninterestingPut(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + scUninteresting := ffs.StorageConfig{} + err := ts.Put(iid, c, scUninteresting) + require.NoError(t, err) + + requireRepairables(t, ts) +} + +func TestRevertedPut(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + // Add some repariable + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c, scRepairable) + require.NoError(t, err) + requireRepairables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) + + // Put again but not repariable, should be gone. + scUninteresting := ffs.StorageConfig{} + err = ts.Put(iid, c, scUninteresting) + require.NoError(t, err) + requireRepairables(t, ts) +} + +func TestPutRenewableRepairable(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c, scRepairableRenewable) + require.NoError(t, err) + + requireRepairables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) + requireRenewables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) +} + +func TestPutRenewableRepairableReverted(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c, scRepairableRenewable) + require.NoError(t, err) + err = ts.Put(iid, c, scRenewable) + require.NoError(t, err) + requireRepairables(t, ts) + requireRenewables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) +} + +func TestPutRenewableSwitchRepairable(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c, scRenewable) + require.NoError(t, err) + requireRenewables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) + + err = ts.Put(iid, c, scRepairable) + require.NoError(t, err) + requireRenewables(t, ts) + requireRepairables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) +} + +func TestRemove(t *testing.T) { + t.Parallel() + + ts := create(t) + iid := ffs.NewAPIID() + + c, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + err := ts.Put(iid, c, scRenewable) + require.NoError(t, err) + requireRenewables(t, ts, expected{Cid: c, IIDs: []ffs.APIID{iid}}) + + err = ts.Remove(iid, c) + require.NoError(t, err) + + requireRenewables(t, ts) + requireRepairables(t, ts) +} + +func TestPutMultipleIIDsWithRemoves(t *testing.T) { + t.Parallel() + + ts := create(t) + c1, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs81") + c2, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs82") + c3, _ := util.CidFromString("QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs83") + + // IID1: + // - c1 repairable + // - c2 renewable + iid1 := ffs.APIID("1") + err := ts.Put(iid1, c1, scRepairable) + require.NoError(t, err) + err = ts.Put(iid1, c2, scRenewable) + require.NoError(t, err) + + // IID2: + // - c1 repairable + // - c2 renewable + iid2 := ffs.APIID("2") + err = ts.Put(iid2, c1, scRepairable) + require.NoError(t, err) err = ts.Put(iid2, c2, scRenewable) require.NoError(t, err) - scT, iidT, err := ts.Get(c1) + requireRenewables(t, ts, expected{Cid: c2, IIDs: []ffs.APIID{iid1, iid2}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid1, iid2}}) + + // IID3: + // - c1 renewable + // - c3 renewable + iid3 := ffs.APIID("3") + err = ts.Put(iid3, c1, scRenewable) require.NoError(t, err) - require.Equal(t, scRepairable, scT) - require.Equal(t, iid1, iidT) - scT, iidT, err = ts.Get(c2) + err = ts.Put(iid3, c3, scRenewable) require.NoError(t, err) - require.Equal(t, scRenewable, scT) - require.Equal(t, iid2, iidT) - // Check repairables - repairables, err := ts.GetRepairables() + requireRenewables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid3}}, expected{Cid: c2, IIDs: []ffs.APIID{iid1, iid2}}, expected{Cid: c3, IIDs: []ffs.APIID{iid3}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid1, iid2}}) + + // Remove arbitrary and check correctness. + err = ts.Remove(iid2, c2) require.NoError(t, err) - require.Len(t, repairables, 1) - require.Equal(t, c1, repairables[0]) + requireRenewables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid3}}, expected{Cid: c2, IIDs: []ffs.APIID{iid1}}, expected{Cid: c3, IIDs: []ffs.APIID{iid3}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid1, iid2}}) - // Check renewables - renewables, err := ts.GetRenewables() + err = ts.Remove(iid3, c1) require.NoError(t, err) - require.Len(t, renewables, 1) - require.Equal(t, c2, renewables[0]) + requireRenewables(t, ts, expected{Cid: c2, IIDs: []ffs.APIID{iid1}}, expected{Cid: c3, IIDs: []ffs.APIID{iid3}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid1, iid2}}) - // Remove and check correct removals - err = ts.Remove(c1) + err = ts.Remove(iid1, c1) require.NoError(t, err) - _, _, err = ts.Get(c1) - require.Error(t, err) - repairables, err = ts.GetRepairables() + requireRenewables(t, ts, expected{Cid: c2, IIDs: []ffs.APIID{iid1}}, expected{Cid: c3, IIDs: []ffs.APIID{iid3}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid2}}) + + err = ts.Remove(iid1, c2) require.NoError(t, err) - require.Len(t, repairables, 0) + requireRenewables(t, ts, expected{Cid: c3, IIDs: []ffs.APIID{iid3}}) + requireRepairables(t, ts, expected{Cid: c1, IIDs: []ffs.APIID{iid2}}) + + err = ts.Remove(iid2, c1) + require.NoError(t, err) + requireRenewables(t, ts, expected{Cid: c3, IIDs: []ffs.APIID{iid3}}) + requireRepairables(t, ts) - // Test if loading caches works correctly. - err = ts.loadCaches() + err = ts.Remove(iid3, c3) require.NoError(t, err) + requireRenewables(t, ts) + requireRepairables(t, ts) +} + +type expected struct { + Cid cid.Cid + IIDs []ffs.APIID +} + +func requireRepairables(t *testing.T, ts *Store, exp ...expected) { + t.Helper() + tcs, err := ts.GetRepairables() + require.NoError(t, err) + require.Len(t, tcs, len(exp)) + + sortTC(tcs) + for i := range exp { + require.Equal(t, exp[i].Cid, tcs[i].Cid) + for j := range exp[i].IIDs { + require.Equal(t, exp[i].IIDs[j], tcs[i].Tracked[j].IID) + require.True(t, tcs[i].Tracked[j].StorageConfig.Repairable) + } + } +} + +func requireRenewables(t *testing.T, ts *Store, exp ...expected) { + t.Helper() + tcs, err := ts.GetRenewables() + require.NoError(t, err) + require.Len(t, tcs, len(exp)) + + sortTC(tcs) + for i := range exp { + require.Equal(t, exp[i].Cid, tcs[i].Cid) + for j := range exp[i].IIDs { + require.Equal(t, exp[i].IIDs[j], tcs[i].Tracked[j].IID) + sc := tcs[i].Tracked[j].StorageConfig + require.True(t, sc.Cold.Enabled) + require.True(t, sc.Cold.Filecoin.Renew.Enabled) + } + } +} + +func sortTC(tcs []TrackedCid) { + sort.Slice(tcs, func(i, j int) bool { + return tcs[i].Cid.String() < tcs[j].Cid.String() + }) + for _, tc := range tcs { + sort.Slice(tc.Tracked, func(i, j int) bool { + return tc.Tracked[i].IID.String() < tc.Tracked[j].IID.String() + }) + } } func create(t *testing.T) *Store { diff --git a/ffs/scheduler/scheduler.go b/ffs/scheduler/scheduler.go index b56fc2078..45973b7c4 100644 --- a/ffs/scheduler/scheduler.go +++ b/ffs/scheduler/scheduler.go @@ -54,10 +54,13 @@ type Scheduler struct { sr2RepFactor func() (int, error) dealFinalityTimeout time.Duration - sd storageDaemon - rd retrievalDaemon - cancelLock sync.Mutex - cancelChans map[ffs.JobID]chan struct{} + gcLock sync.Mutex + gc GCConfig + + sd storageDaemon + rd retrievalDaemon + cancelLock sync.Mutex + jobsCancel map[ffs.JobID]chan struct{} ctx context.Context cancel context.CancelFunc @@ -78,9 +81,15 @@ type retrievalDaemon struct { evaluateQueue chan struct{} } +// GCConfig provides configuration for FFS GC. +type GCConfig struct { + StageGracePeriod time.Duration + AutoGCInterval time.Duration +} + // New returns a new instance of Scheduler which uses JobStore as its backing repository for state, -// HotStorage for hot storage, and ColdStorage for cold storage. -func New(ds datastore.TxnDatastore, l ffs.JobLogger, hs ffs.HotStorage, cs ffs.ColdStorage, maxParallel int, dealFinalityTimeout time.Duration, sr2rf func() (int, error)) (*Scheduler, error) { +// HotStorage for the hot layer, and ColdStorage for the cold layer. +func New(ds datastore.TxnDatastore, l ffs.JobLogger, hs ffs.HotStorage, cs ffs.ColdStorage, maxParallel int, dealFinalityTimeout time.Duration, sr2rf func() (int, error), gcConfig GCConfig) (*Scheduler, error) { sjs, err := sjstore.New(txndstr.Wrap(ds, "sjstore")) if err != nil { return nil, fmt.Errorf("loading stroage jobstore: %s", err) @@ -95,7 +104,7 @@ func New(ds datastore.TxnDatastore, l ffs.JobLogger, hs ffs.HotStorage, cs ffs.C return nil, fmt.Errorf("loading scheduler trackstore: %s", err) } - cis := cistore.New(txndstr.Wrap(ds, "cistore")) + cis := cistore.New(txndstr.Wrap(ds, "cistore_v2")) ris := ristore.New(txndstr.Wrap(ds, "ristore")) ctx, cancel := context.WithCancel(context.Background()) @@ -112,9 +121,10 @@ func New(ds datastore.TxnDatastore, l ffs.JobLogger, hs ffs.HotStorage, cs ffs.C cis: cis, ris: ris, - l: l, + l: l, + gc: gcConfig, - cancelChans: make(map[ffs.JobID]chan struct{}), + jobsCancel: make(map[ffs.JobID]chan struct{}), sd: storageDaemon{ rateLim: make(chan struct{}, maxParallel), evaluateQueue: make(chan struct{}, 1), @@ -131,7 +141,9 @@ func New(ds datastore.TxnDatastore, l ffs.JobLogger, hs ffs.HotStorage, cs ffs.C sr2RepFactor: sr2rf, dealFinalityTimeout: dealFinalityTimeout, } + go sch.run() + return sch, nil } @@ -148,7 +160,7 @@ func (s *Scheduler) GetCidFromHot(ctx context.Context, c cid.Cid) (io.Reader, er func (s *Scheduler) Cancel(jid ffs.JobID) error { s.cancelLock.Lock() defer s.cancelLock.Unlock() - cancelChan, ok := s.cancelChans[jid] + cancelChan, ok := s.jobsCancel[jid] if !ok { return nil } @@ -163,6 +175,50 @@ func (s *Scheduler) Cancel(jid ffs.JobID) error { return nil } +// GCStaged runs a unpinned garbage collection of stage-pins. +func (s *Scheduler) GCStaged(ctx context.Context) ([]cid.Cid, error) { + return s.gcStaged(ctx, 0) +} + +// PinnedCids returns the pinned cids from Hot-Storage. +func (s *Scheduler) PinnedCids(ctx context.Context) ([]ffs.PinnedCid, error) { + res, err := s.hs.PinnedCids(ctx) + if err != nil { + return nil, fmt.Errorf("getting pinned cids from hot-storage: %s", err) + } + return res, nil +} + +func (s *Scheduler) gcStaged(ctx context.Context, gracePeriod time.Duration) ([]cid.Cid, error) { + s.gcLock.Lock() + defer s.gcLock.Unlock() + log.Infof("running scheduler gc...") + cids := map[cid.Cid]struct{}{} + + qj := s.sjs.QueuedJobs(ffs.EmptyInstanceID) + for _, j := range qj { + cids[j.Cid] = struct{}{} + } + ej := s.sjs.ExecutingJobs(ffs.EmptyInstanceID) + for _, j := range ej { + cids[j.Cid] = struct{}{} + } + + excludedCids := make([]cid.Cid, 0, len(cids)) + for c := range cids { + excludedCids = append(excludedCids, c) + } + + gced, err := s.hs.GCStaged(ctx, excludedCids, time.Now().Add(-gracePeriod)) + if err != nil { + return nil, fmt.Errorf("hot-storage gc: %s", err) + } + + log.Infof("scheduler gc ran with %d excluded cids, unpinning %d staged cids", len(excludedCids), len(gced)) + + return gced, nil +} + // Close terminates the scheduler. func (s *Scheduler) Close() error { log.Info("closing...") @@ -176,15 +232,36 @@ func (s *Scheduler) Close() error { } // run spins the long-running goroutines that will execute -// queued storage and retrieval jobs, renewals and repairs. +// queued storage, retrieval jobs, renewals, repairs, and gc. func (s *Scheduler) run() { defer close(s.finished) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + if s.gc.AutoGCInterval == 0 { + return + } + + for { + select { + case <-s.ctx.Done(): + return + case <-time.After(s.gc.AutoGCInterval): + if _, err := s.gcStaged(s.ctx, s.gc.StageGracePeriod); err != nil { + log.Errorf("automatic gc: %s", err) + } + } + } + }() + if err := s.resumeStartedDeals(); err != nil { log.Errorf("resuming started deals: %s", err) return } - var wg sync.WaitGroup // Timer for evaluating renewable storage configs. wg.Add(1) go func() { @@ -291,23 +368,22 @@ func (s *Scheduler) resumeStartedDeals() error { // it has repairing semantics too. If no work is needed, this scheduled // job would have no real work done. func (s *Scheduler) execRepairCron(ctx context.Context) { - cids, err := s.ts.GetRepairables() + tcids, err := s.ts.GetRepairables() if err != nil { log.Errorf("getting repairable cid configs from store: %s", err) return } - for _, c := range cids { - if ctx.Err() != nil { - log.Info("repair cron execution canceled") - break - } - lCtx := context.WithValue(ctx, ffs.CtxStorageCid, c) - s.l.Log(lCtx, "Scheduling deal repair evaluation...") - jid, err := s.scheduleRenewRepairJob(c) - if err != nil { - s.l.Log(lCtx, "Scheduling deal repair errored: %s", err) - } else { - s.l.Log(lCtx, "Job %s was queued for repair evaluation.", jid) + for _, tc := range tcids { + for _, sc := range tc.Tracked { + lCtx := context.WithValue(ctx, ffs.CtxStorageCid, tc.Cid) + lCtx = context.WithValue(lCtx, ffs.CtxAPIID, sc.IID) + s.l.Log(lCtx, "Scheduling deal repair evaluation...") + jid, err := s.push(sc.IID, tc.Cid, sc.StorageConfig, cid.Undef) + if err != nil { + s.l.Log(lCtx, "Scheduling deal repair errored: %s", err) + } else { + s.l.Log(lCtx, "Job %s was queued for repair evaluation.", jid) + } } } } @@ -316,38 +392,25 @@ func (s *Scheduler) execRepairCron(ctx context.Context) { // reschedule them as if they were pushed. The scheduler main executing logic // will do renewals if necessary. func (s *Scheduler) execRenewCron(ctx context.Context) { - cids, err := s.ts.GetRenewables() + tcids, err := s.ts.GetRenewables() if err != nil { log.Errorf("getting repairable cid configs from store: %s", err) } - for _, c := range cids { - if ctx.Err() != nil { - log.Infof("renew cron execution canceled") - return - } - lCtx := context.WithValue(ctx, ffs.CtxStorageCid, c) - s.l.Log(lCtx, "Scheduling deal renew evaluation...") - jid, err := s.scheduleRenewRepairJob(c) - if err != nil { - s.l.Log(lCtx, "Scheduling deal renewal errored: %s", err) - } else { - s.l.Log(lCtx, "Job %s was queued for renew evaluation.", jid) + for _, tc := range tcids { + for _, sc := range tc.Tracked { + lCtx := context.WithValue(ctx, ffs.CtxStorageCid, tc.Cid) + lCtx = context.WithValue(lCtx, ffs.CtxAPIID, sc.IID) + s.l.Log(lCtx, "Scheduling deal renew evaluation...") + jid, err := s.push(sc.IID, tc.Cid, sc.StorageConfig, cid.Undef) + if err != nil { + s.l.Log(lCtx, "Scheduling deal renewal errored: %s", err) + } else { + s.l.Log(lCtx, "Job %s was queued for renew evaluation.", jid) + } } } } -func (s *Scheduler) scheduleRenewRepairJob(c cid.Cid) (ffs.JobID, error) { - sc, iid, err := s.ts.Get(c) - if err != nil { - return "", fmt.Errorf("getting latest storage config: %s", err) - } - jid, err := s.push(iid, c, sc, cid.Undef) - if err != nil { - return "", fmt.Errorf("scheduling repair job: %s", err) - } - return jid, nil -} - func (s *Scheduler) execQueuedStorages(ctx context.Context) { var err error var j *ffs.StorageJob @@ -396,17 +459,18 @@ func (s *Scheduler) executeQueuedStorage(j ffs.StorageJob) { cancelChan := make(chan struct{}, 1) // Create chan to allow Job cancellation. s.cancelLock.Lock() - s.cancelChans[j.ID] = cancelChan + s.jobsCancel[j.ID] = cancelChan s.cancelLock.Unlock() defer func() { s.cancelLock.Lock() - delete(s.cancelChans, j.ID) + delete(s.jobsCancel, j.ID) s.cancelLock.Unlock() }() ctx, cancel := context.WithCancel(context.WithValue(context.Background(), ffs.CtxKeyJid, j.ID)) defer cancel() ctx = context.WithValue(ctx, ffs.CtxStorageCid, j.Cid) + ctx = context.WithValue(ctx, ffs.CtxAPIID, j.APIID) var cancelLock sync.Mutex var canceled bool @@ -414,10 +478,10 @@ func (s *Scheduler) executeQueuedStorage(j ffs.StorageJob) { // If the user called Cancel to cancel Job execution, // we cancel the context to finish. <-cancelChan - cancel() cancelLock.Lock() canceled = true cancelLock.Unlock() + cancel() }() // Get @@ -464,6 +528,7 @@ func (s *Scheduler) executeQueuedStorage(j ffs.StorageJob) { if err := s.sjs.Finalize(j.ID, finalStatus, nil, dealErrors); err != nil { log.Errorf("changing job to success: %s", err) } + s.l.Log(ctx, "Job %s execution finished with status %s.", j.ID, ffs.JobStatusStr[finalStatus]) } @@ -515,11 +580,11 @@ func (s *Scheduler) executeQueuedRetrievals(j ffs.RetrievalJob) { cancelChan := make(chan struct{}) // Create chan to allow Job cancellation. s.cancelLock.Lock() - s.cancelChans[j.ID] = cancelChan + s.jobsCancel[j.ID] = cancelChan s.cancelLock.Unlock() defer func() { s.cancelLock.Lock() - delete(s.cancelChans, j.ID) + delete(s.jobsCancel, j.ID) s.cancelLock.Unlock() }() diff --git a/ffs/scheduler/scheduler_retrieval.go b/ffs/scheduler/scheduler_retrieval.go index 199f05432..1f206ff04 100644 --- a/ffs/scheduler/scheduler_retrieval.go +++ b/ffs/scheduler/scheduler_retrieval.go @@ -92,7 +92,7 @@ func (s *Scheduler) executeRetrieval(ctx context.Context, a astore.RetrievalActi // ToDo: use graphsync to get the underlying DataCid to be pinned dataCid := cid.Undef - size, err := s.hs.Store(ctx, dataCid) + size, err := s.hs.Pin(ctx, a.APIID, dataCid) if err != nil { return ffs.RetrievalInfo{}, fmt.Errorf("pinning data cid: %s", err) } diff --git a/ffs/scheduler/scheduler_storage.go b/ffs/scheduler/scheduler_storage.go index aafdd361b..645ace757 100644 --- a/ffs/scheduler/scheduler_storage.go +++ b/ffs/scheduler/scheduler_storage.go @@ -57,6 +57,7 @@ func (s *Scheduler) push(iid ffs.APIID, c cid.Cid, cfg ffs.StorageConfig, oldCid ctx := context.WithValue(context.Background(), ffs.CtxKeyJid, jid) ctx = context.WithValue(ctx, ffs.CtxStorageCid, c) + ctx = context.WithValue(ctx, ffs.CtxAPIID, iid) s.l.Log(ctx, "Pushing new configuration...") aa := astore.StorageAction{ @@ -76,7 +77,7 @@ func (s *Scheduler) push(iid ffs.APIID, c cid.Cid, cfg ffs.StorageConfig, oldCid if err := s.sjs.Enqueue(j); err != nil { return ffs.EmptyJobID, fmt.Errorf("enqueuing job: %s", err) } - if jid := s.sjs.GetExecutingJob(c); jid != nil { + if jid := s.sjs.GetExecutingJob(iid, c); jid != nil { s.l.Log(ctx, "Job %s is already being executed for the same data, this job will be queued until it finishes or is canceled.", jid) } @@ -89,18 +90,18 @@ func (s *Scheduler) push(iid ffs.APIID, c cid.Cid, cfg ffs.StorageConfig, oldCid return jid, nil } -// Untrack untracks a Cid for renewal and repair background crons. -func (s *Scheduler) Untrack(c cid.Cid) error { - if err := s.ts.Remove(c); err != nil { +// Untrack untracks a Cid from iid for renewal and repair background crons. +func (s *Scheduler) Untrack(iid ffs.APIID, c cid.Cid) error { + if err := s.ts.Remove(iid, c); err != nil { return fmt.Errorf("removing cid from action store: %s", err) } return nil } -// GetStorageInfo returns the current storage state of a Cid. Returns ErrNotFound +// GetStorageInfo returns the current storage state of a Cid for a APIID. Returns ErrNotFound // if there isn't information for a Cid. -func (s *Scheduler) GetStorageInfo(c cid.Cid) (ffs.StorageInfo, error) { - info, err := s.cis.Get(c) +func (s *Scheduler) GetStorageInfo(iid ffs.APIID, c cid.Cid) (ffs.StorageInfo, error) { + info, err := s.cis.Get(iid, c) if err == cistore.ErrNotFound { return ffs.StorageInfo{}, ErrNotFound } @@ -112,8 +113,8 @@ func (s *Scheduler) GetStorageInfo(c cid.Cid) (ffs.StorageInfo, error) { // ImportStorageInfo imports Cid information manually. That's to say, will be StorageInfo // which wasn't generated by executing a Job, but provided externally. -func (s *Scheduler) ImportStorageInfo(ci ffs.StorageInfo) error { - _, err := s.cis.Get(ci.Cid) +func (s *Scheduler) ImportStorageInfo(iid ffs.APIID, ci ffs.StorageInfo) error { + _, err := s.cis.Get(iid, ci.Cid) if err != nil && err != cistore.ErrNotFound { return fmt.Errorf("checking if cid info already exists: %s", err) } @@ -151,8 +152,8 @@ func (s *Scheduler) WatchLogs(ctx context.Context, c chan<- ffs.LogEntry) error } // GetLogsByCid returns history logs of a Cid. -func (s *Scheduler) GetLogsByCid(ctx context.Context, c cid.Cid) ([]ffs.LogEntry, error) { - lgs, err := s.l.GetByCid(ctx, c) +func (s *Scheduler) GetLogsByCid(ctx context.Context, iid ffs.APIID, c cid.Cid) ([]ffs.LogEntry, error) { + lgs, err := s.l.GetByCid(ctx, iid, c) if err != nil { return nil, fmt.Errorf("getting logs: %s", err) } @@ -203,34 +204,47 @@ func (s *Scheduler) StorageConfig(jid ffs.JobID) (ffs.StorageConfig, error) { // should be considered failed. If error is nil, it still can return []ffs.DealError // since some deals failing isn't necessarily a fatal Job config execution. func (s *Scheduler) executeStorage(ctx context.Context, a astore.StorageAction, job ffs.StorageJob, dealUpdates chan deals.StorageDealInfo) (ffs.StorageInfo, []ffs.DealError, error) { - ci, err := s.getRefreshedInfo(ctx, a.Cid) + ci, err := s.getRefreshedInfo(ctx, a.APIID, a.Cid) if err != nil { return ffs.StorageInfo{}, nil, fmt.Errorf("getting current cid info from store: %s", err) } if a.ReplacedCid.Defined() { - if err := s.Untrack(a.ReplacedCid); err != nil && err != astore.ErrNotFound { + if err := s.Untrack(a.APIID, a.ReplacedCid); err != nil && err != astore.ErrNotFound { return ffs.StorageInfo{}, nil, fmt.Errorf("untracking replaced cid: %s", err) } } - s.l.Log(ctx, "Ensuring Hot-Storage satisfies the configuration...") - hot, err := s.executeHotStorage(ctx, ci, a.Cfg.Hot, a.Cfg.Cold.Filecoin.Addr, a.ReplacedCid) - if err != nil { - s.l.Log(ctx, "Hot-Storage excution failed.") - return ffs.StorageInfo{}, nil, fmt.Errorf("executing hot-storage config: %s", err) + var hot ffs.HotInfo + if a.Cfg.Hot.Enabled { + s.l.Log(ctx, "Executing Hot-Storage configuration...") + hot, err = s.executeEnabledHotStorage(ctx, a.APIID, ci, a.Cfg.Hot, a.Cfg.Cold.Filecoin.Addr, a.ReplacedCid) + if err != nil { + s.l.Log(ctx, "Enabled Hot-Storage excution failed.") + return ffs.StorageInfo{}, nil, fmt.Errorf("executing enabled hot-storage: %s", err) + } + s.l.Log(ctx, "Hot-Storage configuration ran successfully.") } - s.l.Log(ctx, "Hot-Storage execution ran successfully.") - s.l.Log(ctx, "Ensuring Cold-Storage satisfies the configuration...") + s.l.Log(ctx, "Executing Cold-Storage configuration...") cold, errors, err := s.executeColdStorage(ctx, ci, a.Cfg.Cold, dealUpdates) if err != nil { s.l.Log(ctx, "Cold-Storage execution failed.") return ffs.StorageInfo{}, errors, fmt.Errorf("executing cold-storage config: %s", err) } - s.l.Log(ctx, "Cold-Storage execution ran successfully.") + s.l.Log(ctx, "Cold-Storage configuration ran successfully.") + + if !a.Cfg.Hot.Enabled { + s.l.Log(ctx, "Executing Hot-Storage configuration...") + if err := s.executeDisabledHotStorage(ctx, a.APIID, a.Cid); err != nil { + s.l.Log(ctx, "Disabled Hot-Storage execution failed.") + return ffs.StorageInfo{}, nil, fmt.Errorf("executing disabled hot-storage: %s", err) + } + s.l.Log(ctx, "Hot-Storage configuration ran successfully.") + } return ffs.StorageInfo{ + APIID: a.APIID, JobID: job.ID, Cid: a.Cid, Hot: hot, @@ -239,18 +253,29 @@ func (s *Scheduler) executeStorage(ctx context.Context, a astore.StorageAction, }, errors, nil } -func (s *Scheduler) executeHotStorage(ctx context.Context, curr ffs.StorageInfo, cfg ffs.HotConfig, waddr string, replaceCid cid.Cid) (ffs.HotInfo, error) { - if cfg.Enabled == curr.Hot.Enabled { - s.l.Log(ctx, "No actions needed in Hot Storage.") - return curr.Hot, nil +// ensureCorrectPinning ensures that the Cid has the correct pinning flag in hot storage. +func (s *Scheduler) executeDisabledHotStorage(ctx context.Context, iid ffs.APIID, c cid.Cid) error { + ok, err := s.hs.IsPinned(ctx, iid, c) + if err != nil { + return fmt.Errorf("getting pinned status: %s", err) + } + if !ok { + s.l.Log(ctx, "Data was already unpinned.") + return nil } + if err := s.hs.Unpin(ctx, iid, c); err != nil { + return fmt.Errorf("unpinning cid %s: %s", c, err) + } + s.l.Log(ctx, "Data was unpinned.") - if !cfg.Enabled { - if err := s.hs.Remove(ctx, curr.Cid); err != nil { - return ffs.HotInfo{}, fmt.Errorf("removing from hot storage: %s", err) - } - s.l.Log(ctx, "Cid successfully removed from Hot Storage.") - return ffs.HotInfo{Enabled: false}, nil + return nil +} + +// executeEnabledHotStorageEnabled runs the logic if the Job has Hot Storage enabled. +func (s *Scheduler) executeEnabledHotStorage(ctx context.Context, iid ffs.APIID, curr ffs.StorageInfo, cfg ffs.HotConfig, waddr string, replaceCid cid.Cid) (ffs.HotInfo, error) { + if curr.Hot.Enabled { + s.l.Log(ctx, "No actions needed in enabling Hot Storage.") + return curr.Hot, nil } // ToDo: this is a hot-fix to force a big timeout until we have a @@ -261,10 +286,10 @@ func (s *Scheduler) executeHotStorage(ctx context.Context, curr ffs.StorageInfo, var size int var err error if !replaceCid.Defined() { - size, err = s.hs.Store(sctx, curr.Cid) + size, err = s.hs.Pin(sctx, iid, curr.Cid) } else { s.l.Log(ctx, "Replace of previous pin %s", replaceCid) - size, err = s.hs.Replace(sctx, replaceCid, curr.Cid) + size, err = s.hs.Replace(sctx, iid, replaceCid, curr.Cid) } if err != nil { s.l.Log(ctx, "Direct fetching from IPFS wasn't possible.") @@ -290,7 +315,7 @@ func (s *Scheduler) executeHotStorage(ctx context.Context, curr ffs.StorageInfo, return ffs.HotInfo{}, fmt.Errorf("unfreezing from Cold Storage: %s", err) } s.l.Log(ctx, "Unfrozen successfully from %s with cost %d attoFil, saving in Hot-Storage...", fi.RetrievedMiner, fi.FundsSpent) - size, err = s.hs.Store(ctx, curr.Cold.Filecoin.DataCid) + size, err = s.hs.Pin(ctx, iid, curr.Cold.Filecoin.DataCid) if err != nil { return ffs.HotInfo{}, fmt.Errorf("pinning unfrozen cid: %s", err) } @@ -304,17 +329,17 @@ func (s *Scheduler) executeHotStorage(ctx context.Context, curr ffs.StorageInfo, }, nil } -func (s *Scheduler) getRefreshedInfo(ctx context.Context, c cid.Cid) (ffs.StorageInfo, error) { +func (s *Scheduler) getRefreshedInfo(ctx context.Context, iid ffs.APIID, c cid.Cid) (ffs.StorageInfo, error) { var err error - ci, err := s.cis.Get(c) + ci, err := s.cis.Get(iid, c) if err != nil { if err != cistore.ErrNotFound { return ffs.StorageInfo{}, ErrNotFound } - return ffs.StorageInfo{Cid: c}, nil // Default value has both storages disabled + return ffs.StorageInfo{Cid: c, APIID: iid}, nil // Default value has both storages disabled } - ci.Hot, err = s.getRefreshedHotInfo(ctx, c, ci.Hot) + ci.Hot, err = s.getRefreshedHotInfo(ctx, iid, c, ci.Hot) if err != nil { return ffs.StorageInfo{}, fmt.Errorf("getting refreshed hot info: %s", err) } @@ -327,9 +352,9 @@ func (s *Scheduler) getRefreshedInfo(ctx context.Context, c cid.Cid) (ffs.Storag return ci, nil } -func (s *Scheduler) getRefreshedHotInfo(ctx context.Context, c cid.Cid, curr ffs.HotInfo) (ffs.HotInfo, error) { +func (s *Scheduler) getRefreshedHotInfo(ctx context.Context, iid ffs.APIID, c cid.Cid, curr ffs.HotInfo) (ffs.HotInfo, error) { var err error - curr.Enabled, err = s.hs.IsStored(ctx, c) + curr.Enabled, err = s.hs.IsPinned(ctx, iid, c) if err != nil { return ffs.HotInfo{}, err } @@ -366,7 +391,7 @@ func (s *Scheduler) executeColdStorage(ctx context.Context, curr ffs.StorageInfo // 1. If we recognize there were some unfinished started deals, then // Powergate was closed while that was being executed. If that's the case // we resume tracking those deals until they finish. - sds, err := s.sjs.GetStartedDeals(curr.Cid) + sds, err := s.sjs.GetStartedDeals(curr.APIID, curr.Cid) if err != nil { return ffs.ColdInfo{}, nil, fmt.Errorf("checking for started deals: %s", err) } @@ -378,6 +403,11 @@ func (s *Scheduler) executeColdStorage(ctx context.Context, curr ffs.StorageInfo allErrors = append(allErrors, failedResumedDeals...) // Append the resumed and confirmed deals to the current active proposals curr.Cold.Filecoin.Proposals = append(okResumedDeals, curr.Cold.Filecoin.Proposals...) + + // We can already clean resumed started deals. + if err := s.sjs.RemoveStartedDeals(curr.APIID, curr.Cid); err != nil { + return ffs.ColdInfo{}, allErrors, fmt.Errorf("removing resumed started deals storage: %s", err) + } } // 2. If this Storage Config is renewable, then let's check if any of the existing deals @@ -457,14 +487,14 @@ func (s *Scheduler) executeColdStorage(ctx context.Context, curr ffs.StorageInfo // Track all deals that weren't rejected, just in case Powergate crashes/closes before // we see them finalize, so they can be detected and resumed on starting Powergate again (point 1. above) - if err := s.sjs.AddStartedDeals(curr.Cid, startedProposals); err != nil { + if err := s.sjs.AddStartedDeals(curr.APIID, curr.Cid, startedProposals); err != nil { return ffs.ColdInfo{}, rejectedProposals, err } // Wait for started deals. okDeals, failedDeals := s.waitForDeals(ctx, curr.Cid, startedProposals, dealUpdates) allErrors = append(allErrors, failedDeals...) - if err := s.sjs.RemoveStartedDeals(curr.Cid); err != nil { + if err := s.sjs.RemoveStartedDeals(curr.APIID, curr.Cid); err != nil { return ffs.ColdInfo{}, allErrors, fmt.Errorf("removing temporal started deals storage: %s", err) } diff --git a/ffs/types.go b/ffs/types.go index 41be277d5..72097ccff 100644 --- a/ffs/types.go +++ b/ffs/types.go @@ -412,6 +412,9 @@ type RetrievalInfo struct { // StorageInfo contains information about the current storage state // of a Cid. type StorageInfo struct { + // APIID indicate from which instance this + // information belongs. + APIID APIID // JobID indicates the Job ID which updated // the current information. It *may be empty* if // the data was imported manually. @@ -502,17 +505,21 @@ const ( // CtxRetrievalID is the context-key to indicate the RetrievalID of // a RetrievalJob for JobLogger. CtxRetrievalID + // CtxAPIID is the context-key to indicate which APIID owns the log + // entry. + CtxAPIID ) // JobLogger saves log information about a storage and retrieval tasks. type JobLogger interface { Log(context.Context, string, ...interface{}) Watch(context.Context, chan<- LogEntry) error - GetByCid(context.Context, cid.Cid) ([]LogEntry, error) + GetByCid(context.Context, APIID, cid.Cid) ([]LogEntry, error) } // LogEntry is a log entry from a Cid execution. type LogEntry struct { + APIID APIID Cid cid.Cid Timestamp time.Time Jid JobID diff --git a/gateway/gateway.go b/gateway/gateway.go index e8f320d5a..1032d7ec7 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -152,7 +152,6 @@ func (g *Gateway) asksHandler(c *gin.Context) { index := g.askIndex.Get() subtitle := fmt.Sprintf("Last updated: %v, storage median price: %v", timeToString(index.LastUpdated), index.StorageMedianPrice) - headers := []string{"Miner", "Price", "Min Piece Size", "Max Piece Size", "Timestamp", "Expiry"} rows := make([][]interface{}, len(index.Storage)) diff --git a/go.mod b/go.mod index 21bdd653c..f7fa2902d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/textileio/powergate -go 1.14 +go 1.15 require ( contrib.go.opencensus.io/exporter/prometheus v0.2.0 @@ -32,6 +32,7 @@ require ( github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 github.com/ipfs/interface-go-ipfs-core v0.4.0 github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 + github.com/json-iterator/go v1.1.10 // indirect github.com/libp2p/go-libp2p v0.12.0 github.com/libp2p/go-libp2p-core v0.7.0 github.com/libp2p/go-libp2p-kad-dht v0.11.0 diff --git a/go.sum b/go.sum index caec81551..b70520c59 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,7 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1 dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -632,6 +633,7 @@ github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjv github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-badger v0.2.3 h1:J27YvAcpuA5IvZUbeBxOcQgqnYHUPxoygc6QxxkodZ4= github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= github.com/ipfs/go-ds-badger2 v0.1.0 h1:784py6lXkwlVF+K6XSuqmdMgy5l8GI6k60ngBokb9Fg= github.com/ipfs/go-ds-badger2 v0.1.0/go.mod h1:pbR1p817OZbdId9EvLOhKBgUVTM3BMCSTan78lDDVaw= @@ -850,6 +852,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -2198,6 +2202,7 @@ google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/index/ask/runner/runner.go b/index/ask/runner/runner.go index f6c6da997..6c314ce64 100644 --- a/index/ask/runner/runner.go +++ b/index/ask/runner/runner.go @@ -241,7 +241,7 @@ func generateIndex(ctx context.Context, api *apistruct.FullNodeStruct, maxParall newAsks[addr.String()] = sask lock.Unlock() }(addr) - if i%100 == 0 { + if i%5000 == 0 { stats.Record(context.Background(), metrics.MFullRefreshProgress.M(float64(i)/float64(len(addrs)))) log.Infof("progress %d/%d", i, len(addrs)) } diff --git a/migration/migration.go b/migration/migration.go new file mode 100644 index 000000000..9250f5c00 --- /dev/null +++ b/migration/migration.go @@ -0,0 +1,198 @@ +package migration + +import ( + "encoding/json" + "fmt" + + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + logger "github.com/ipfs/go-log/v2" +) + +var ( + log = logger.Logger("migrations") + + keyCurrentVersion = datastore.NewKey("version") +) + +// Migrator ensures a datastore goes through all the needed +// Migrations to upgrade its current version to the latest version. +type Migrator struct { + ds datastore.TxnDatastore + migrations map[int]Migration +} + +type datastoreReaderWriter interface { + datastore.Read + datastore.Write +} + +// Migration runs a vA->v(A+1) migration. UseTxn indicates +// if this migration should be run in a transaction. +type Migration struct { + Run func(datastoreReaderWriter) error + UseTxn bool +} + +// New returns a new Migrator. +func New(ds datastore.TxnDatastore, migrations map[int]Migration) *Migrator { + m := &Migrator{ + ds: ds, + migrations: migrations, + } + return m +} + +// Ensure detects the current datastore version, and runs all the known migrations +// to upgrade to the latest known version. +func (m *Migrator) Ensure() error { + currentVersion, emptyDS, err := m.getCurrentVersion() + if err != nil { + return fmt.Errorf("getting current version: %s", err) + } + + targetVersion := m.getTargetVersion() + + // If the database is empty, we can assume Powergate started fresh + // and requires no migration. Set current version to latest version + // in migrations script. + if emptyDS { + if err := m.bootstrapEmptyDatastore(targetVersion); err != nil { + return fmt.Errorf("bootstrapping empty database: %s", err) + } + + return nil + } + + log.Infof("Current datastore version is %d, target version %d", currentVersion, targetVersion) + + if currentVersion == targetVersion { + return nil + } + + if currentVersion > targetVersion { + return fmt.Errorf("migrations are forward only, current version %d, target version %d", currentVersion, targetVersion) + } + + for i := currentVersion + 1; i <= targetVersion; i++ { + log.Infof("Running %d migration...", i) + if err := m.run(i); err != nil { + return fmt.Errorf("running migration %d: %s", i, err) + } + log.Infof("Migration %d ran successfully", i) + } + + return nil +} + +type currentVersion struct { + Version int +} + +// getCurrentVersion returns the current database version. If it isn't one +// defined wil be 0. If the datastore is considered to be completely empty, +// it returns true in the second return parameter. +func (m *Migrator) getCurrentVersion() (int, bool, error) { + isDSEmpty, err := m.isDSEmpty() + if err != nil { + return 0, false, fmt.Errorf("detecting if datastore is empty: %s", err) + } + if isDSEmpty { + return 0, true, nil + } + + var current currentVersion + buf, err := m.ds.Get(keyCurrentVersion) + if err == datastore.ErrNotFound { + return 0, false, nil + } + if err != nil { + return 0, false, fmt.Errorf("getting version from datastore: %s", err) + } + + if err := json.Unmarshal(buf, ¤t); err != nil { + return 0, false, fmt.Errorf("unmarshaling current version: %s", err) + } + + return current.Version, false, nil +} + +func (m *Migrator) run(version int) error { + var dsReaderWriter datastoreReaderWriter + + migration, ok := m.migrations[version] + if !ok { + return fmt.Errorf("migration script not found") + } + + dsReaderWriter = m.ds + if migration.UseTxn { + txn, err := m.ds.NewTransaction(false) + if err != nil { + return fmt.Errorf("creating txn for migration: %s", err) + } + defer txn.Discard() + dsReaderWriter = txn + } + + if err := migration.Run(dsReaderWriter); err != nil { + return fmt.Errorf("running migration script: %s", err) + } + + newVer := currentVersion{Version: version} + newVerBuf, err := json.Marshal(newVer) + if err != nil { + return fmt.Errorf("marshaling new version: %s", err) + } + if err := dsReaderWriter.Put(keyCurrentVersion, newVerBuf); err != nil { + return fmt.Errorf("saving new version: %s", err) + } + + if migration.UseTxn { + txn := dsReaderWriter.(datastore.Txn) + if err := txn.Commit(); err != nil { + return fmt.Errorf("committing transaction: %s", err) + } + } + + return nil +} + +func (m *Migrator) isDSEmpty() (bool, error) { + q := query.Query{Limit: 1} + res, err := m.ds.Query(q) + if err != nil { + return false, fmt.Errorf("executing query: %s", err) + } + defer func() { _ = res.Close() }() + + all, err := res.Rest() + if err != nil { + return false, fmt.Errorf("getting query results: %s", err) + } + + return len(all) == 0, nil +} + +func (m *Migrator) getTargetVersion() int { + var maxVersion int + for ver := range m.migrations { + if ver > maxVersion { + maxVersion = ver + } + } + return maxVersion +} + +func (m *Migrator) bootstrapEmptyDatastore(version int) error { + newVer := currentVersion{Version: version} + newVerBuf, err := json.Marshal(newVer) + if err != nil { + return fmt.Errorf("marshaling new version: %s", err) + } + if err := m.ds.Put(keyCurrentVersion, newVerBuf); err != nil { + return fmt.Errorf("saving new version: %s", err) + } + + return nil +} diff --git a/migration/migration1.go b/migration/migration1.go new file mode 100644 index 000000000..ea1ddfe08 --- /dev/null +++ b/migration/migration1.go @@ -0,0 +1,233 @@ +package migration + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/util" +) + +// V1MultitenancyMigration contains the logic to upgrade a datastore from +// version 0 to version 1. Transactionality is disabled since is a big migration. +var V1MultitenancyMigration = Migration{ + UseTxn: false, + Run: func(ds datastoreReaderWriter) error { + cidOwners, err := v0CidOwners(ds) + if err != nil { + return fmt.Errorf("getting cid owners: %s", err) + } + log.Infof("Starting job logger migration...") + if err := migrateJobLogger(ds, cidOwners); err != nil { + return fmt.Errorf("migrating job logger: %s", err) + } + log.Infof("Job logger migration finished") + + log.Infof("Starting storage info migration...") + if err := migrateStorageInfo(ds, cidOwners); err != nil { + return fmt.Errorf("migrating storage info: %s", err) + } + log.Infof("Storage info migration finished") + + log.Infof("Starting trackstore migration...") + if err := migrateTrackstore(ds, cidOwners); err != nil { + return fmt.Errorf("migrating trackstore: %s", err) + } + log.Infof("Trackstore migration finished") + + log.Infof("Starting started deals migration...") + if err := migrateStartedDeals(ds); err != nil { + return fmt.Errorf("migrating trackstore: %s", err) + } + log.Infof("Started deals migration finished") + + log.Infof("Starting pinstore filling migration...") + if err := pinstoreFilling(ds, cidOwners); err != nil { + return fmt.Errorf("filling pinstore: %s", err) + } + log.Infof("Pinstore filling migration finished") + + return nil + }, +} + +func v0CidOwners(ds datastoreReaderWriter) (map[cid.Cid][]ffs.APIID, error) { + iids, err := v0APIIDs(ds) + if err != nil { + return nil, fmt.Errorf("getting v0 iids: %s", err) + } + + lim := make(chan struct{}, 1000) + var lock sync.Mutex + var errors []string + owners := map[cid.Cid][]ffs.APIID{} + for _, iid := range iids { + lim <- struct{}{} + iid := iid + go func() { + defer func() { <-lim }() + cids, err := v0GetCidsFromIID(ds, iid) + if err != nil { + lock.Lock() + errors = append(errors, fmt.Sprintf("getting cids from iid: %s", err)) + lock.Unlock() + return + } + lock.Lock() + for _, c := range cids { + owners[c] = append(owners[c], iid) + } + lock.Unlock() + }() + } + + for i := 0; i < len(lim); i++ { + lim <- struct{}{} + } + + if len(errors) > 0 { + for _, m := range errors { + log.Error(m) + } + return nil, fmt.Errorf("building cidowners had %d errors", len(errors)) + } + + return owners, nil +} + +func v0GetCidsFromIID(ds datastoreReaderWriter, iid ffs.APIID) ([]cid.Cid, error) { + q := query.Query{Prefix: "/ffs/manager/api/" + iid.String() + "/istore/cidstorageconfig"} + res, err := ds.Query(q) + if err != nil { + return nil, fmt.Errorf("getting cids from iid: %s", err) + } + defer func() { + _ = res.Close() + }() + + var ret []cid.Cid + for r := range res.Next() { + if r.Error != nil { + return nil, fmt.Errorf("query result: %s", r.Error) + } + + // /ffs/manager/api//istore/cidstorageconfig/ + cidStr := datastore.NewKey(r.Key).Namespaces()[6] + c, err := util.CidFromString(cidStr) + if err != nil { + return nil, fmt.Errorf("discovered invalid cid: %s", err) + } + ret = append(ret, c) + } + + return ret, nil +} + +func v0APIIDs(ds datastoreReaderWriter) ([]ffs.APIID, error) { + q := query.Query{Prefix: "/ffs/manager/api"} + res, err := ds.Query(q) + if err != nil { + return nil, fmt.Errorf("getting iids: %s", err) + } + defer func() { + _ = res.Close() + }() + + iids := map[ffs.APIID]struct{}{} + for r := range res.Next() { + if r.Error != nil { + return nil, fmt.Errorf("query result: %s", r.Error) + } + + k := datastore.NewKey(r.Key) + iid := ffs.APIID(k.Namespaces()[3]) // /ffs/manager/api//... + if !iid.Valid() { + return nil, fmt.Errorf("discovered invalid iid: %s", err) + } + iids[iid] = struct{}{} + } + + ret := make([]ffs.APIID, 0, len(iids)) + for iid := range iids { + ret = append(ret, iid) + } + + return ret, nil +} + +func v0GetStorageConfig(ds datastoreReaderWriter, iid ffs.APIID, c cid.Cid) (ffs.StorageConfig, error) { + if !iid.Valid() { + return ffs.StorageConfig{}, fmt.Errorf("invalid iid %s", iid) + } + if !c.Defined() { + return ffs.StorageConfig{}, fmt.Errorf("undefined cid") + } + key := datastore.NewKey("/ffs/manager/api/" + iid.String() + "/istore/cidstorageconfig/" + util.CidToString(c)) + + buf, err := ds.Get(key) + if err != nil { + return ffs.StorageConfig{}, fmt.Errorf("getting storage config: %s", err) + } + var conf ffs.StorageConfig + if err := json.Unmarshal(buf, &conf); err != nil { + return ffs.StorageConfig{}, fmt.Errorf("unmarshaling cid config from datastore: %s", err) + } + + return conf, nil +} + +func v0GetExecutingJobs(ds datastoreReaderWriter) (map[cid.Cid]ffs.APIID, error) { + q := query.Query{Prefix: "/ffs/scheduler/sjstore/job"} // /ffs/scheduler/sjstore/job/ + res, err := ds.Query(q) + if err != nil { + return nil, fmt.Errorf("getting jobs: %s", err) + } + defer func() { + _ = res.Close() + }() + + lim := make(chan struct{}, 1000) + var lock sync.Mutex + var errors []string + ret := map[cid.Cid]ffs.APIID{} + for r := range res.Next() { + if r.Error != nil { + return nil, fmt.Errorf("getting result from query: %s", r.Error) + } + lim <- struct{}{} + r := r + go func() { + defer func() { <-lim }() + + var j ffs.StorageJob + if err := json.Unmarshal(r.Value, &j); err != nil { + lock.Lock() + errors = append(errors, fmt.Sprintf("unmarshalling job: %s", err)) + lock.Unlock() + return + } + if j.Status == ffs.Executing { + lock.Lock() + ret[j.Cid] = j.APIID + lock.Unlock() + } + }() + } + + for i := 0; i < cap(lim); i++ { + lim <- struct{}{} + } + + if len(errors) > 0 { + for _, m := range errors { + log.Error(m) + } + return nil, fmt.Errorf("building executing jobs map had %d errors", len(errors)) + } + + return ret, nil +} diff --git a/migration/migration1_joblogger.go b/migration/migration1_joblogger.go new file mode 100644 index 000000000..f8d6cff78 --- /dev/null +++ b/migration/migration1_joblogger.go @@ -0,0 +1,84 @@ +package migration + +import ( + "fmt" + "sync" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/util" +) + +func migrateJobLogger(ds datastoreReaderWriter, cidOwners map[cid.Cid][]ffs.APIID) error { + q := query.Query{Prefix: "/ffs/joblogger"} + res, err := ds.Query(q) + if err != nil { + return fmt.Errorf("querying joblogger: %s", err) + } + defer func() { _ = res.Close() }() + + var lock sync.Mutex + var errors []string + lim := make(chan struct{}, 1000) + for r := range res.Next() { + if r.Error != nil { + return fmt.Errorf("iterating result: %s", r.Error) + } + lim <- struct{}{} + + r := r + go func() { + defer func() { <-lim }() + + originalKey := datastore.NewKey(r.Key) + cidStr := originalKey.Namespaces()[2] // /ffs/joblogger// + cid, err := util.CidFromString(cidStr) + if err != nil { + lock.Lock() + errors = append(errors, fmt.Sprintf("parsing cid %s: %s", cidStr, err)) + lock.Unlock() + return + } + timestampStr := originalKey.Namespaces()[3] + + owners := cidOwners[cid] + + // Step 1/2: + // For each cid owner, we create the same registry + // in the new key version. + for _, iid := range owners { + newKey := datastore.NewKey("/ffs/joblogger_v2/").ChildString(iid.String()).ChildString(cidStr).ChildString(timestampStr) + if err := ds.Put(newKey, r.Value); err != nil { + lock.Lock() + errors = append(errors, fmt.Sprintf("copying job log: %s", err)) + lock.Unlock() + return + } + } + + // Step 2/2: + // Delete old datastore key. + if err := ds.Delete(originalKey); err != nil { + lock.Lock() + errors = append(errors, fmt.Sprintf("deleting old key: %s", err)) + lock.Unlock() + return + } + }() + } + + for i := 0; i < cap(lim); i++ { + lim <- struct{}{} + } + + if len(errors) > 0 { + for _, m := range errors { + log.Error(m) + } + return fmt.Errorf("migration had %d errors", len(errors)) + } + + return nil +} diff --git a/migration/migration1_joblogger_test.go b/migration/migration1_joblogger_test.go new file mode 100644 index 000000000..86b1253b9 --- /dev/null +++ b/migration/migration1_joblogger_test.go @@ -0,0 +1,32 @@ +package migration + +import ( + "testing" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/tests" + "github.com/textileio/powergate/util" +) + +func TestV1_JobLogger(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_JobLogger.pre") + + c1, _ := util.CidFromString("QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE") + c2, _ := util.CidFromString("QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M") + cidOwners := map[cid.Cid][]ffs.APIID{ + c1: {ffs.APIID("ID1"), ffs.APIID("ID2")}, + c2: {ffs.APIID("ID3")}, + } + txn, _ := ds.NewTransaction(false) + err := migrateJobLogger(txn, cidOwners) + require.NoError(t, err) + require.NoError(t, txn.Commit()) + + post(t, ds, "testdata/v1_JobLogger.post") +} diff --git a/migration/migration1_pinstore.go b/migration/migration1_pinstore.go new file mode 100644 index 000000000..16d325613 --- /dev/null +++ b/migration/migration1_pinstore.go @@ -0,0 +1,92 @@ +package migration + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/textileio/powergate/ffs" +) + +// The following two datastructures are +// what Pinstore in v1 expects to be saved +// in the datastore. We can't use pinstore.PinnedCid +// struct directly because is an `internal` package. +type v1PinstorePinnedCid struct { + Cid cid.Cid + Pins []v1PinstorePin +} +type v1PinstorePin struct { + APIID ffs.APIID + Staged bool + CreatedAt int64 +} + +func pinstoreFilling(ds datastoreReaderWriter, cidOwners map[cid.Cid][]ffs.APIID) error { + // This migration should fill Pinstore. Pinstore keeps track of + // which IIDs are pinning a Cid in hot-storage. + + // Step 1/2: + // - Iterate over all cidOwners and make a list of + // IIDs that are pinning a Cid in hot-storage. + var lock sync.Mutex + var errors []string + lim := make(chan struct{}, 1000) + cidsPinstore := map[cid.Cid][]ffs.APIID{} + for c, iids := range cidOwners { + lim <- struct{}{} + c := c + iids := iids + go func() { + defer func() { <-lim }() + for _, iid := range iids { + sc, err := v0GetStorageConfig(ds, iid, c) + if err != nil { + lock.Lock() + errors = append(errors, fmt.Sprintf("getting storage config: %s", err)) + lock.Unlock() + return + } + if sc.Hot.Enabled { + lock.Lock() + cidsPinstore[c] = append(cidsPinstore[c], iid) + lock.Unlock() + } + } + }() + } + + for i := 0; i < cap(lim); i++ { + lim <- struct{}{} + } + + // Step 2/2: + // - Include this generated data in Pinstore. + for c, iids := range cidsPinstore { + if len(iids) == 0 { + continue + } + r := v1PinstorePinnedCid{ + Cid: c, + Pins: make([]v1PinstorePin, len(iids)), + } + for i := range iids { + r.Pins[i] = v1PinstorePin{ + APIID: iids[i], + CreatedAt: 0, + } + } + k := datastore.NewKey("/ffs/coreipfs/pinstore/pins/" + r.Cid.String()) + buf, err := json.Marshal(r) + if err != nil { + return fmt.Errorf("marshaling to datastore: %s", err) + } + if err := ds.Put(k, buf); err != nil { + return fmt.Errorf("put in datastore: %s", err) + } + } + + return nil +} diff --git a/migration/migration1_pinstore_test.go b/migration/migration1_pinstore_test.go new file mode 100644 index 000000000..11dc41ebf --- /dev/null +++ b/migration/migration1_pinstore_test.go @@ -0,0 +1,32 @@ +package migration + +import ( + "testing" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/tests" + "github.com/textileio/powergate/util" +) + +func TestV1_Pinstore(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_Pinstore.pre") + + c1, _ := util.CidFromString("QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus") + c2, _ := util.CidFromString("QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq") + cidOwners := map[cid.Cid][]ffs.APIID{ + c1: {ffs.APIID("ad2f3b0c-e356-43d4-a483-fba79479d7e4"), ffs.APIID("fb79f525-a3c4-47f0-94e5-e344c5b1dec5")}, + c2: {ffs.APIID("2bef4790-a47a-4a48-90da-a89f93ab6310")}, + } + txn, _ := ds.NewTransaction(false) + err := pinstoreFilling(txn, cidOwners) + require.NoError(t, err) + require.NoError(t, txn.Commit()) + + post(t, ds, "testdata/v1_Pinstore.post") +} diff --git a/migration/migration1_starteddeals.go b/migration/migration1_starteddeals.go new file mode 100644 index 000000000..8e05f8173 --- /dev/null +++ b/migration/migration1_starteddeals.go @@ -0,0 +1,53 @@ +package migration + +import ( + "fmt" + + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + "github.com/textileio/powergate/util" +) + +func migrateStartedDeals(ds datastoreReaderWriter) error { + executingJobs, err := v0GetExecutingJobs(ds) + if err != nil { + return fmt.Errorf("getting executing jobs: %s", err) + } + q := query.Query{Prefix: "/ffs/scheduler/sjstore/starteddeals"} + res, err := ds.Query(q) + if err != nil { + return fmt.Errorf("querying started deals in sjstore: %s", err) + } + defer func() { _ = res.Close() }() + + for r := range res.Next() { + if r.Error != nil { + return fmt.Errorf("iterating result: %s", r.Error) + } + + originalKey := datastore.NewKey(r.Key) + cidStr := originalKey.Namespaces()[4] // /ffs/scheduler/sjstore/starteddeals/ + cid, err := util.CidFromString(cidStr) + if err != nil { + return fmt.Errorf("discovered invalid cid: %s", err) + } + + owner, ok := executingJobs[cid] + if ok { + // Step 1/2: + // Add corresponding iid in started deals key namespace. + newKey := datastore.NewKey("/ffs/scheduler/sjstore/starteddeals_v2").ChildString(owner.String()).ChildString(cidStr) + if err := ds.Put(newKey, r.Value); err != nil { + return fmt.Errorf("copying started deal to new key: %s", err) + } + } + + // Step 2/2: + // Delete old datastore key. + if err := ds.Delete(originalKey); err != nil { + return fmt.Errorf("deleting old key: %s", err) + } + } + + return nil +} diff --git a/migration/migration1_starteddeals_test.go b/migration/migration1_starteddeals_test.go new file mode 100644 index 000000000..99a4c1464 --- /dev/null +++ b/migration/migration1_starteddeals_test.go @@ -0,0 +1,47 @@ +package migration + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/tests" + "github.com/textileio/powergate/util" +) + +func TestV1_StartedDeals(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_StartedDeals.pre") + + txn, _ := ds.NewTransaction(false) + err := migrateStartedDeals(txn) + require.NoError(t, err) + require.NoError(t, txn.Commit()) + + post(t, ds, "testdata/v1_StartedDeals.post") +} + +func TestV0_ExecutingJobs(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_StartedDeals.pre") + + txn, _ := ds.NewTransaction(false) + execJobsOwners, err := v0GetExecutingJobs(txn) + require.NoError(t, err) + + require.Len(t, execJobsOwners, 2) + + c1, _ := util.CidFromString("QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5") + iid1 := ffs.APIID("a9aeaecc-4c94-4bb6-bd14-13927d8cede0") + require.Equal(t, iid1, execJobsOwners[c1]) + + c2, _ := util.CidFromString("QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q") + iid2 := ffs.APIID("ad2f3b0c-e356-43d4-a483-fba79479d7e4") + require.Equal(t, iid2, execJobsOwners[c2]) +} diff --git a/migration/migration1_storageinfo.go b/migration/migration1_storageinfo.go new file mode 100644 index 000000000..87597db92 --- /dev/null +++ b/migration/migration1_storageinfo.go @@ -0,0 +1,63 @@ +package migration + +import ( + "encoding/json" + "fmt" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/util" +) + +func migrateStorageInfo(ds datastoreReaderWriter, cidOwners map[cid.Cid][]ffs.APIID) error { + q := query.Query{Prefix: "/ffs/scheduler/cistore"} + res, err := ds.Query(q) + if err != nil { + return fmt.Errorf("querying cistore: %s", err) + } + defer func() { _ = res.Close() }() + + for r := range res.Next() { + if r.Error != nil { + return fmt.Errorf("iterating result: %s", r.Error) + } + + originalKey := datastore.NewKey(r.Key) + cidStr := originalKey.Namespaces()[3] // /ffs/scheduler/cistore/ + cid, err := util.CidFromString(cidStr) + if err != nil { + return fmt.Errorf("discovered invalid cid: %s", err) + } + + owners := cidOwners[cid] + // Step 1/2: + // For each cid owner, we create the same registry + // prexifing the iid considering the new namespace structure. + for _, iid := range owners { + var si ffs.StorageInfo + if err := json.Unmarshal(r.Value, &si); err != nil { + return fmt.Errorf("unmarshaling storageconfig: %s", err) + } + si.APIID = iid + buf, err := json.Marshal(si) + if err != nil { + return fmt.Errorf("marshaling now entry: %s", err) + } + + newKey := datastore.NewKey("/ffs/scheduler/cistore_v2").ChildString(iid.String()).ChildString(cidStr) + if err := ds.Put(newKey, buf); err != nil { + return fmt.Errorf("copying storageinfo: %s", err) + } + } + + // Step 2/2: + // Delete old datastore key. + if err := ds.Delete(originalKey); err != nil { + return fmt.Errorf("deleting old key: %s", err) + } + } + + return nil +} diff --git a/migration/migration1_storageinfo_test.go b/migration/migration1_storageinfo_test.go new file mode 100644 index 000000000..6e3dbe0b2 --- /dev/null +++ b/migration/migration1_storageinfo_test.go @@ -0,0 +1,32 @@ +package migration + +import ( + "testing" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/tests" + "github.com/textileio/powergate/util" +) + +func TestV1_StorageInfo(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_StorageInfo.pre") + + c1, _ := util.CidFromString("QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR") + c2, _ := util.CidFromString("QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M") + cidOwners := map[cid.Cid][]ffs.APIID{ + c1: {ffs.APIID("ID1"), ffs.APIID("ID2")}, + c2: {ffs.APIID("ID2"), ffs.APIID("ID3")}, + } + txn, _ := ds.NewTransaction(false) + err := migrateStorageInfo(txn, cidOwners) + require.NoError(t, err) + require.NoError(t, txn.Commit()) + + post(t, ds, "testdata/v1_StorageInfo.post") +} diff --git a/migration/migration1_trackstore.go b/migration/migration1_trackstore.go new file mode 100644 index 000000000..7b60d306b --- /dev/null +++ b/migration/migration1_trackstore.go @@ -0,0 +1,71 @@ +package migration + +import ( + "encoding/json" + "fmt" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/util" +) + +type v0trackedStorageConfig struct { + IID ffs.APIID + StorageConfig ffs.StorageConfig +} + +// In v1 we persist the same struct but as an array, instead +// of a single element. +type v1trackedStorageConfig v0trackedStorageConfig + +func migrateTrackstore(ds datastoreReaderWriter, cidOwners map[cid.Cid][]ffs.APIID) error { + q := query.Query{Prefix: "/ffs/scheduler/tstore"} + res, err := ds.Query(q) + if err != nil { + return fmt.Errorf("querying tstore: %s", err) + } + defer func() { _ = res.Close() }() + + for r := range res.Next() { + if r.Error != nil { + return fmt.Errorf("iterating result: %s", r.Error) + } + + originalKey := datastore.NewKey(r.Key) + cidStr := originalKey.Namespaces()[3] // /ffs/scheduler/tstore/ + cid, err := util.CidFromString(cidStr) + if err != nil { + return fmt.Errorf("discovered invalid cid: %s", err) + } + + // Step 1/2: + // For each cid owner, we replace the registry + // with a slice of owners. + owners := cidOwners[cid] + newEntry := make([]v1trackedStorageConfig, len(owners)) + for i, iid := range owners { + sg, err := v0GetStorageConfig(ds, iid, cid) + if err != nil { + return fmt.Errorf("get storage config of cid from owner: %s", err) + } + + if sg.Repairable || (sg.Cold.Enabled && sg.Cold.Filecoin.Renew.Enabled) { + newEntry[i] = v1trackedStorageConfig{IID: iid, StorageConfig: sg} + } + } + + // Step 2/2: + // Replace original entry with new entry. + buf, err := json.Marshal(newEntry) + if err != nil { + return fmt.Errorf("marshaling new entry: %s", err) + } + if err := ds.Put(originalKey, buf); err != nil { + return fmt.Errorf("put new entry in datastore: %s", err) + } + } + + return nil +} diff --git a/migration/migration1_trackstore_test.go b/migration/migration1_trackstore_test.go new file mode 100644 index 000000000..aeb8dbb98 --- /dev/null +++ b/migration/migration1_trackstore_test.go @@ -0,0 +1,96 @@ +package migration + +import ( + "sort" + "testing" + + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" + "github.com/textileio/powergate/ffs" + "github.com/textileio/powergate/tests" + "github.com/textileio/powergate/util" +) + +func TestV1_Trackstore(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_Trackstore.pre") + + c1, _ := util.CidFromString("QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus") + c2, _ := util.CidFromString("QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq") + cidOwners := map[cid.Cid][]ffs.APIID{ + c1: {ffs.APIID("ad2f3b0c-e356-43d4-a483-fba79479d7e4"), ffs.APIID("fb79f525-a3c4-47f0-94e5-e344c5b1dec5")}, + c2: {ffs.APIID("2bef4790-a47a-4a48-90da-a89f93ab6310")}, + } + txn, _ := ds.NewTransaction(false) + err := migrateTrackstore(txn, cidOwners) + require.NoError(t, err) + require.NoError(t, txn.Commit()) + + post(t, ds, "testdata/v1_Trackstore.post") +} + +func TestV0_APIIDs(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_Trackstore.pre") + + txn, _ := ds.NewTransaction(false) + iids, err := v0APIIDs(txn) + require.NoError(t, err) + + sort.Slice(iids, func(i, j int) bool { + return iids[i].String() < iids[j].String() + }) + + require.Len(t, iids, 3) + require.Equal(t, "2bef4790-a47a-4a48-90da-a89f93ab6310", iids[0].String()) + require.Equal(t, "ad2f3b0c-e356-43d4-a483-fba79479d7e4", iids[1].String()) + require.Equal(t, "fb79f525-a3c4-47f0-94e5-e344c5b1dec5", iids[2].String()) +} + +func TestV0_GetCidsFromIID(t *testing.T) { + t.Parallel() + + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_Trackstore.pre") + + txn, _ := ds.NewTransaction(false) + cids, err := v0GetCidsFromIID(txn, "ad2f3b0c-e356-43d4-a483-fba79479d7e4") + require.NoError(t, err) + + require.Len(t, cids, 1) + require.Equal(t, "QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus", cids[0].String()) +} + +func TestV0_CidOwners(t *testing.T) { + t.Parallel() + c1, _ := util.CidFromString("QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus") + c2, _ := util.CidFromString("QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq") + expectedOwners := map[cid.Cid][]ffs.APIID{ + c1: {ffs.APIID("ad2f3b0c-e356-43d4-a483-fba79479d7e4"), ffs.APIID("fb79f525-a3c4-47f0-94e5-e344c5b1dec5")}, + c2: {ffs.APIID("2bef4790-a47a-4a48-90da-a89f93ab6310")}, + } + ds := tests.NewTxMapDatastore() + + pre(t, ds, "testdata/v1_Trackstore.pre") + + txn, _ := ds.NewTransaction(false) + owners, err := v0CidOwners(txn) + require.NoError(t, err) + + require.Equal(t, len(expectedOwners), len(owners)) + for k1, v1 := range expectedOwners { + v2, ok := owners[k1] + require.True(t, ok) + sort.Slice(v2, func(i, j int) bool { + return v2[i].String() < v2[j].String() + }) + require.Equal(t, v1, v2) + } +} diff --git a/migration/migration_test.go b/migration/migration_test.go new file mode 100644 index 000000000..48dc69768 --- /dev/null +++ b/migration/migration_test.go @@ -0,0 +1,332 @@ +package migration + +import ( + "bufio" + "context" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/query" + badger "github.com/ipfs/go-ds-badger2" + "github.com/stretchr/testify/require" + mongods "github.com/textileio/go-ds-mongo" + "github.com/textileio/powergate/tests" + + logger "github.com/ipfs/go-log/v2" +) + +func TestEmptyDatastore(t *testing.T) { + t.Parallel() + + ms := map[int]Migration{ + 1: { + UseTxn: true, + Run: func(_ datastoreReaderWriter) error { + return fmt.Errorf("This migration shouldn't be run on empty database") + }, + }, + } + m := newMigrator(ms, true) + + v, empty, err := m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 0, v) + require.True(t, empty) + + err = m.Ensure() + require.NoError(t, err) + + v, _, err = m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 1, v) +} + +func TestNonEmptyDatastore(t *testing.T) { + t.Parallel() + + ms := map[int]Migration{ + 1: { + UseTxn: true, + Run: func(_ datastoreReaderWriter) error { + return nil + }, + }, + } + m := newMigrator(ms, false) + + v, empty, err := m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 0, v) + require.False(t, empty) + + err = m.Ensure() + require.NoError(t, err) + + v, _, err = m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 1, v) +} + +func TestForwardOnly(t *testing.T) { + t.Parallel() + + ms := map[int]Migration{ + 1: { + UseTxn: true, + Run: func(_ datastoreReaderWriter) error { + return nil + }, + }, + } + + m := newMigrator(ms, false) + err := m.bootstrapEmptyDatastore(10) + require.NoError(t, err) + + v, _, err := m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 10, v) + + err = m.Ensure() + require.Error(t, err) +} + +func TestNoop(t *testing.T) { + t.Parallel() + + ms := map[int]Migration{ + 1: { + UseTxn: true, + Run: func(_ datastoreReaderWriter) error { + return nil + }, + }, + } + m := newMigrator(ms, false) + + err := m.Ensure() + require.NoError(t, err) + + err = m.Ensure() + require.NoError(t, err) +} + +func TestFailingMigration(t *testing.T) { + ms := map[int]Migration{ + 1: { + UseTxn: true, + Run: func(_ datastoreReaderWriter) error { + return fmt.Errorf("I failed") + }, + }, + } + m := newMigrator(ms, false) + + v, _, err := m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 0, v) + + err = m.Ensure() + require.Error(t, err) + + v, _, err = m.getCurrentVersion() + require.NoError(t, err) + require.Equal(t, 0, v) +} + +func TestRealDataBadger(t *testing.T) { + logger.SetDebugLogging() + _ = logger.SetLogLevel("badger", "error") + tmpDir := t.TempDir() + err := copyDir("testdata/badgerdump", tmpDir+"/badgerdump") + require.NoError(t, err) + + opts := &badger.DefaultOptions + ds, err := badger.NewDatastore(tmpDir+"/badgerdump", opts) + require.NoError(t, err) + defer func() { require.NoError(t, ds.Close()) }() + + migrations := map[int]Migration{ + 1: V1MultitenancyMigration, + } + m := New(ds, migrations) + err = m.Ensure() + require.NoError(t, err) +} + +func TestRealDataRemoteMongo(t *testing.T) { + t.SkipNow() + logger.SetDebugLogging() + mongoCtx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + mongoURI := "" + mongoDB := "" + ds, err := mongods.New(mongoCtx, mongoURI, mongoDB, mongods.WithCollName("migration_kvstore"), mongods.WithOpTimeout(time.Hour), mongods.WithTxnTimeout(time.Hour)) + require.NoError(t, err) + defer func() { require.NoError(t, ds.Close()) }() + + migrations := map[int]Migration{ + 1: V1MultitenancyMigration, + } + m := New(ds, migrations) + err = m.Ensure() + require.NoError(t, err) +} + +func newMigrator(migrations map[int]Migration, empty bool) *Migrator { + ds := tests.NewTxMapDatastore() + m := New(ds, migrations) + + if !empty { + _ = ds.Put(datastore.NewKey("foo"), []byte("bar")) + } + + return m +} + +func pre(t *testing.T, ds datastore.TxnDatastore, path string) { + t.Helper() + f, err := os.Open(path) + require.NoError(t, err) + defer func() { require.NoError(t, f.Close()) }() + + s := bufio.NewScanner(f) + for s.Scan() { + parts := strings.SplitN(s.Text(), ",", 2) + err = ds.Put(datastore.NewKey(parts[0]), []byte(parts[1])) + require.NoError(t, err) + } +} + +func post(t *testing.T, ds datastore.TxnDatastore, path string) { + t.Helper() + + f, err := os.Open(path) + require.NoError(t, err) + defer func() { require.NoError(t, f.Close()) }() + + current := map[string][]byte{} + q := query.Query{} + res, err := ds.Query(q) + require.NoError(t, err) + defer func() { require.NoError(t, res.Close()) }() + for r := range res.Next() { + require.NoError(t, r.Error) + current[r.Key] = r.Value + } + + expected := map[string][]byte{} + s := bufio.NewScanner(f) + for s.Scan() { + parts := strings.SplitN(s.Text(), ",", 2) + expected[parts[0]] = []byte(parts[1]) + } + + require.Equal(t, len(expected), len(current)) + for k1, v1 := range current { + v2, ok := expected[k1] + require.True(t, ok) + require.Equal(t, v2, v1) + } +} + +func copyFile(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer func() { _ = in.Close() }() + + out, err := os.Create(dst) + if err != nil { + return + } + defer func() { + if e := out.Close(); e != nil { + err = e + } + }() + + _, err = io.Copy(out, in) + if err != nil { + return + } + + err = out.Sync() + if err != nil { + return + } + + si, err := os.Stat(src) + if err != nil { + return + } + err = os.Chmod(dst, si.Mode()) + if err != nil { + return + } + + return +} + +func copyDir(src string, dst string) (err error) { + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + si, err := os.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + err = os.MkdirAll(dst, si.Mode()) + if err != nil { + return + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return + } + + for _, entry := range entries { + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + err = copyDir(srcPath, dstPath) + if err != nil { + return + } + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err = copyFile(srcPath, dstPath) + if err != nil { + return + } + } + } + + return +} diff --git a/migration/testdata/badgerdump/000000.vlog b/migration/testdata/badgerdump/000000.vlog new file mode 100644 index 000000000..42c240244 Binary files /dev/null and b/migration/testdata/badgerdump/000000.vlog differ diff --git a/migration/testdata/badgerdump/000002.sst b/migration/testdata/badgerdump/000002.sst new file mode 100644 index 000000000..7411237a8 Binary files /dev/null and b/migration/testdata/badgerdump/000002.sst differ diff --git a/migration/testdata/badgerdump/KEYREGISTRY b/migration/testdata/badgerdump/KEYREGISTRY new file mode 100644 index 000000000..5e598590e --- /dev/null +++ b/migration/testdata/badgerdump/KEYREGISTRY @@ -0,0 +1 @@ +pËn1Ç2qó‡Yçæ²üHello Badger \ No newline at end of file diff --git a/migration/testdata/badgerdump/MANIFEST b/migration/testdata/badgerdump/MANIFEST new file mode 100644 index 000000000..38fd7248d Binary files /dev/null and b/migration/testdata/badgerdump/MANIFEST differ diff --git a/migration/testdata/v1_JobLogger.post b/migration/testdata/v1_JobLogger.post new file mode 100644 index 000000000..abbe2d353 --- /dev/null +++ b/migration/testdata/v1_JobLogger.post @@ -0,0 +1,3 @@ +/ffs/joblogger_v2/ID1/QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE/1602952162298722885,{"Cid":{"/":"QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE"},"RetrievalID":"","Timestamp":1602952162298722885,"Jid":"ad6da2a0-5465-4275-a330-2537062765c8","Msg":"Deal 763168 with miner f022142 is active on-chain"} +/ffs/joblogger_v2/ID2/QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE/1602952162298722885,{"Cid":{"/":"QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE"},"RetrievalID":"","Timestamp":1602952162298722885,"Jid":"ad6da2a0-5465-4275-a330-2537062765c8","Msg":"Deal 763168 with miner f022142 is active on-chain"} +/ffs/joblogger_v2/ID3/QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M/1603115031102317344,{"Cid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"RetrievalID":"","Timestamp":1603115031102317344,"Jid":"35a6f8fc-cad5-41f4-a410-e5c3d882f0e0","Msg":"Proposing deal to miner f022142 with 200000000 attoFIL per epoch..."} diff --git a/migration/testdata/v1_JobLogger.pre b/migration/testdata/v1_JobLogger.pre new file mode 100644 index 000000000..801c342fb --- /dev/null +++ b/migration/testdata/v1_JobLogger.pre @@ -0,0 +1,2 @@ +/ffs/joblogger/QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE/1602952162298722885,{"Cid":{"/":"QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE"},"RetrievalID":"","Timestamp":1602952162298722885,"Jid":"ad6da2a0-5465-4275-a330-2537062765c8","Msg":"Deal 763168 with miner f022142 is active on-chain"} +/ffs/joblogger/QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M/1603115031102317344,{"Cid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"RetrievalID":"","Timestamp":1603115031102317344,"Jid":"35a6f8fc-cad5-41f4-a410-e5c3d882f0e0","Msg":"Proposing deal to miner f022142 with 200000000 attoFIL per epoch..."} diff --git a/migration/testdata/v1_Pinstore.post b/migration/testdata/v1_Pinstore.post new file mode 100644 index 000000000..c4c9a490e --- /dev/null +++ b/migration/testdata/v1_Pinstore.post @@ -0,0 +1,6 @@ +/ffs/coreipfs/pinstore/pins/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Cid":{"/":"QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus"},"Pins":[{"APIID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","Staged":false,"CreatedAt":0},{"APIID":"fb79f525-a3c4-47f0-94e5-e344c5b1dec5","Staged":false,"CreatedAt":0}]} +/ffs/coreipfs/pinstore/pins/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,{"Cid":{"/":"QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq"},"Pins":[{"APIID":"2bef4790-a47a-4a48-90da-a89f93ab6310","Staged":false,"CreatedAt":0}]} +/ffs/manager/api/ad2f3b0c-e356-43d4-a483-fba79479d7e4/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":300}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":8,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/fb79f525-a3c4-47f0-94e5-e344c5b1dec5/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":400}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":9,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/2bef4790-a47a-4a48-90da-a89f93ab6310/istore/cidstorageconfig/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/3j124790-a47a-4a48-90da-a89f93ab61a2/istore/cidstorageconfig/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2Gn22,{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} diff --git a/migration/testdata/v1_Pinstore.pre b/migration/testdata/v1_Pinstore.pre new file mode 100644 index 000000000..3d973e514 --- /dev/null +++ b/migration/testdata/v1_Pinstore.pre @@ -0,0 +1,4 @@ +/ffs/manager/api/ad2f3b0c-e356-43d4-a483-fba79479d7e4/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":300}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":8,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/fb79f525-a3c4-47f0-94e5-e344c5b1dec5/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":400}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":9,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/2bef4790-a47a-4a48-90da-a89f93ab6310/istore/cidstorageconfig/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/3j124790-a47a-4a48-90da-a89f93ab61a2/istore/cidstorageconfig/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2Gn22,{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} diff --git a/migration/testdata/v1_StartedDeals.post b/migration/testdata/v1_StartedDeals.post new file mode 100644 index 000000000..5512a6982 --- /dev/null +++ b/migration/testdata/v1_StartedDeals.post @@ -0,0 +1,5 @@ +/ffs/scheduler/sjstore/starteddeals_v2/a9aeaecc-4c94-4bb6-bd14-13927d8cede0/QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5,{"Cid":{"/":"QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5"},"ProposalCids":[{"/":"bafyreieorufsu2rivljkdebak6sncufq5qlkz4wztskr23tau6visrr3ey"},{"/":"bafyreihgbl5jlwja36oi6nxdkp7vfphc3lgbs25c7wtwnao3mdkwbkwy74"},{"/":"bafyreihb6ynz5dzyhv5jup6jxmrqpe4dfkdjrjxs33lzqi2qvsk3jwdja4"},{"/":"bafyreicwjxjusil457xz2hts4bmtlzy24p5dv665phpdbeitbrgvjwus7i"},{"/":"bafyreieowv7aapil35c43y7bgjftj6fli3yljdeno6ubymzrf5ernvjvnm"},{"/":"bafyreiff2rg5vakgxcd7tu5fdefwmojlrthfi3mcgo3mjr5r6j5nx74qim"},{"/":"bafyreic3jyr5pevcdvcp7xstddjwcu5s4oytvhwxeba4mmgrw5pjgvf2nq"},{"/":"bafyreiczqcxwn3qyzq3xlayxcekxtvsoimxpg6lliopxffycnlbg2b5jdq"},{"/":"bafyreig5j5lputtu7fakwzglwe6dul5popbxttaqj74nfpmdbgxmmcr3ge"}]} +/ffs/scheduler/sjstore/starteddeals_v2/ad2f3b0c-e356-43d4-a483-fba79479d7e4/QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q,{"Cid":{"/":"QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q"},"ProposalCids":[{"/":"bafyreifqc26r76rpooet424b2faz6xvvlphm45dxnjq53dk44dqyyvobma"},{"/":"bafyreicn3uklccvzhz4jmq6fncaldcbu6txjs43gzs3kcvrbjsiscyt45y"},{"/":"bafyreigi2vu3w645u7olbeh5iss57sl54xuuhncr5pfvckpmhyd2leiw5q"},{"/":"bafyreifn3aulg7o7rlcjhzn5o5kpucuuienx7rtpvfqgpnk4ncrshcue5i"},{"/":"bafyreiea4q34h6ldhmjabf7butky7lll53eb5d5wnbtbtn6m64po3xaz7a"},{"/":"bafyreihvpdhafuesu6m3ozahda2piwc3anuybpa3xfjpspob6sfe5swyh4"},{"/":"bafyreidyuwyhchuchmilggtzime6nxllq53ciuoyx7qqmz7nh2i7bn3kxm"},{"/":"bafyreihsmyntxpvf7hr6klnl6fjtzxdkgrmriyioxadagjo2ekyq2ljuau"}]} +/ffs/scheduler/sjstore/job/50389563-5925-40c5-8fa9-408ce7c13a6d,{"ID":"50389563-5925-40c5-8fa9-408ce7c13a6d","APIID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","Cid":{"/":"QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5"},"Status":1,"ErrCause":"","DealErrors":[],"CreatedAt":0} +/ffs/scheduler/sjstore/job/61289563-1925-20c5-29a9-308ce7caab21,{"ID":"61289563-1925-20c5-29a9-308ce7caab21","APIID":"a9aeaecc-4c94-4bb6-bd14-13927d8cede0","Cid":{"/":"QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5"},"Status":2,"ErrCause":"","DealErrors":[],"CreatedAt":0} +/ffs/scheduler/sjstore/job/7b63943c-1d14-4d50-b74f-26d63eb3482c,{"ID":"7b63943c-1d14-4d50-b74f-26d63eb3482c","APIID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","Cid":{"/":"QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q"},"Status":2,"ErrCause":"","DealErrors":[],"CreatedAt":0} diff --git a/migration/testdata/v1_StartedDeals.pre b/migration/testdata/v1_StartedDeals.pre new file mode 100644 index 000000000..96e0708ca --- /dev/null +++ b/migration/testdata/v1_StartedDeals.pre @@ -0,0 +1,5 @@ +/ffs/scheduler/sjstore/starteddeals/QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5,{"Cid":{"/":"QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5"},"ProposalCids":[{"/":"bafyreieorufsu2rivljkdebak6sncufq5qlkz4wztskr23tau6visrr3ey"},{"/":"bafyreihgbl5jlwja36oi6nxdkp7vfphc3lgbs25c7wtwnao3mdkwbkwy74"},{"/":"bafyreihb6ynz5dzyhv5jup6jxmrqpe4dfkdjrjxs33lzqi2qvsk3jwdja4"},{"/":"bafyreicwjxjusil457xz2hts4bmtlzy24p5dv665phpdbeitbrgvjwus7i"},{"/":"bafyreieowv7aapil35c43y7bgjftj6fli3yljdeno6ubymzrf5ernvjvnm"},{"/":"bafyreiff2rg5vakgxcd7tu5fdefwmojlrthfi3mcgo3mjr5r6j5nx74qim"},{"/":"bafyreic3jyr5pevcdvcp7xstddjwcu5s4oytvhwxeba4mmgrw5pjgvf2nq"},{"/":"bafyreiczqcxwn3qyzq3xlayxcekxtvsoimxpg6lliopxffycnlbg2b5jdq"},{"/":"bafyreig5j5lputtu7fakwzglwe6dul5popbxttaqj74nfpmdbgxmmcr3ge"}]} +/ffs/scheduler/sjstore/starteddeals/QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q,{"Cid":{"/":"QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q"},"ProposalCids":[{"/":"bafyreifqc26r76rpooet424b2faz6xvvlphm45dxnjq53dk44dqyyvobma"},{"/":"bafyreicn3uklccvzhz4jmq6fncaldcbu6txjs43gzs3kcvrbjsiscyt45y"},{"/":"bafyreigi2vu3w645u7olbeh5iss57sl54xuuhncr5pfvckpmhyd2leiw5q"},{"/":"bafyreifn3aulg7o7rlcjhzn5o5kpucuuienx7rtpvfqgpnk4ncrshcue5i"},{"/":"bafyreiea4q34h6ldhmjabf7butky7lll53eb5d5wnbtbtn6m64po3xaz7a"},{"/":"bafyreihvpdhafuesu6m3ozahda2piwc3anuybpa3xfjpspob6sfe5swyh4"},{"/":"bafyreidyuwyhchuchmilggtzime6nxllq53ciuoyx7qqmz7nh2i7bn3kxm"},{"/":"bafyreihsmyntxpvf7hr6klnl6fjtzxdkgrmriyioxadagjo2ekyq2ljuau"}]} +/ffs/scheduler/sjstore/job/50389563-5925-40c5-8fa9-408ce7c13a6d,{"ID":"50389563-5925-40c5-8fa9-408ce7c13a6d","APIID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","Cid":{"/":"QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5"},"Status":1,"ErrCause":"","DealErrors":[],"CreatedAt":0} +/ffs/scheduler/sjstore/job/61289563-1925-20c5-29a9-308ce7caab21,{"ID":"61289563-1925-20c5-29a9-308ce7caab21","APIID":"a9aeaecc-4c94-4bb6-bd14-13927d8cede0","Cid":{"/":"QmbcKgdxWfZzePsrc6rWq2yk12GE1MnW8JJiubHAJovKb5"},"Status":2,"ErrCause":"","DealErrors":[],"CreatedAt":0} +/ffs/scheduler/sjstore/job/7b63943c-1d14-4d50-b74f-26d63eb3482c,{"ID":"7b63943c-1d14-4d50-b74f-26d63eb3482c","APIID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","Cid":{"/":"QmaPndBy99qcz7rCAooak8SY34Rk9oXWpEBp4dUyhbmq1q"},"Status":2,"ErrCause":"","DealErrors":[],"CreatedAt":0} diff --git a/migration/testdata/v1_StorageInfo.post b/migration/testdata/v1_StorageInfo.post new file mode 100644 index 000000000..66bcfc24f --- /dev/null +++ b/migration/testdata/v1_StorageInfo.post @@ -0,0 +1,4 @@ +/ffs/scheduler/cistore_v2/ID1/QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR,{"APIID":"ID1","JobID":"a84dedc4-b1e5-4798-b4ad-44cc803211ab","Cid":{"/":"QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR"},"Created":"2020-10-07T13:58:24.420077464Z","Hot":{"Enabled":false,"Size":0,"Ipfs":{"Created":"0001-01-01T00:00:00Z"}},"Cold":{"Enabled":true,"Filecoin":{"DataCid":{"/":"QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR"},"Size":33554432,"Proposals":[{"ProposalCid":{"/":"bafyreibncqapiwyvattftvfprmp74vmu47t5jycyvs7ktkejok57dv4maa"},"PieceCid":{"/":"baga6ea4seaqaneh2acoyumk6krvkatezejopmpftygl6ducgrkl7qz7vnrlx2ni"},"Renewed":false,"Duration":519572,"ActivationEpoch":124667,"StartEpoch":132466,"Miner":"t018780","EpochPrice":3125000},{"ProposalCid":{"/":"bafyreigtuke24ml7lsf276676yubcwzswfifgveiaq4l5bvwbgwvofusze"},"PieceCid":{"/":"baga6ea4seaqaneh2acoyumk6krvkatezejopmpftygl6ducgrkl7qz7vnrlx2ni"},"Renewed":false,"Duration":520884,"ActivationEpoch":125745,"StartEpoch":132466,"Miner":"t022352","EpochPrice":3125000000}]}}} +/ffs/scheduler/cistore_v2/ID2/QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR,{"APIID":"ID2","JobID":"a84dedc4-b1e5-4798-b4ad-44cc803211ab","Cid":{"/":"QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR"},"Created":"2020-10-07T13:58:24.420077464Z","Hot":{"Enabled":false,"Size":0,"Ipfs":{"Created":"0001-01-01T00:00:00Z"}},"Cold":{"Enabled":true,"Filecoin":{"DataCid":{"/":"QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR"},"Size":33554432,"Proposals":[{"ProposalCid":{"/":"bafyreibncqapiwyvattftvfprmp74vmu47t5jycyvs7ktkejok57dv4maa"},"PieceCid":{"/":"baga6ea4seaqaneh2acoyumk6krvkatezejopmpftygl6ducgrkl7qz7vnrlx2ni"},"Renewed":false,"Duration":519572,"ActivationEpoch":124667,"StartEpoch":132466,"Miner":"t018780","EpochPrice":3125000},{"ProposalCid":{"/":"bafyreigtuke24ml7lsf276676yubcwzswfifgveiaq4l5bvwbgwvofusze"},"PieceCid":{"/":"baga6ea4seaqaneh2acoyumk6krvkatezejopmpftygl6ducgrkl7qz7vnrlx2ni"},"Renewed":false,"Duration":520884,"ActivationEpoch":125745,"StartEpoch":132466,"Miner":"t022352","EpochPrice":3125000000}]}}} +/ffs/scheduler/cistore_v2/ID2/QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M,{"APIID":"ID2","JobID":"35a6f8fc-cad5-41f4-a410-e5c3d882f0e0","Cid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"Created":"2020-10-20T12:29:12.996702455Z","Hot":{"Enabled":false,"Size":0,"Ipfs":{"Created":"0001-01-01T00:00:00Z"}},"Cold":{"Enabled":true,"Filecoin":{"DataCid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"Size":67108864,"Proposals":[{"ProposalCid":{"/":"bafyreicnwrz4urwfcx3mjrjbglzg4vtjdppcp4ndtbxe35caj3gpzvo7uy"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":521469,"ActivationEpoch":162176,"StartEpoch":168927,"Miner":"f010507","EpochPrice":6250000000},{"ProposalCid":{"/":"bafyreidphishjy4vik3pd43qwspy2pal54z52g7yq5djnp5knolboziyfm"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":519893,"ActivationEpoch":163000,"StartEpoch":168927,"Miner":"f022142","EpochPrice":12500000},{"ProposalCid":{"/":"bafyreibfktn5urhqyhbmoxsnvmjgxmwhmlvs3gjnwsfst4vt7yy5myzj2u"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":520113,"ActivationEpoch":145542,"StartEpoch":149621,"Miner":"f03491","EpochPrice":6250000000}]}}} +/ffs/scheduler/cistore_v2/ID3/QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M,{"APIID":"ID3","JobID":"35a6f8fc-cad5-41f4-a410-e5c3d882f0e0","Cid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"Created":"2020-10-20T12:29:12.996702455Z","Hot":{"Enabled":false,"Size":0,"Ipfs":{"Created":"0001-01-01T00:00:00Z"}},"Cold":{"Enabled":true,"Filecoin":{"DataCid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"Size":67108864,"Proposals":[{"ProposalCid":{"/":"bafyreicnwrz4urwfcx3mjrjbglzg4vtjdppcp4ndtbxe35caj3gpzvo7uy"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":521469,"ActivationEpoch":162176,"StartEpoch":168927,"Miner":"f010507","EpochPrice":6250000000},{"ProposalCid":{"/":"bafyreidphishjy4vik3pd43qwspy2pal54z52g7yq5djnp5knolboziyfm"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":519893,"ActivationEpoch":163000,"StartEpoch":168927,"Miner":"f022142","EpochPrice":12500000},{"ProposalCid":{"/":"bafyreibfktn5urhqyhbmoxsnvmjgxmwhmlvs3gjnwsfst4vt7yy5myzj2u"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":520113,"ActivationEpoch":145542,"StartEpoch":149621,"Miner":"f03491","EpochPrice":6250000000}]}}} diff --git a/migration/testdata/v1_StorageInfo.pre b/migration/testdata/v1_StorageInfo.pre new file mode 100644 index 000000000..a89c723df --- /dev/null +++ b/migration/testdata/v1_StorageInfo.pre @@ -0,0 +1,2 @@ +/ffs/scheduler/cistore/QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR,{"JobID":"a84dedc4-b1e5-4798-b4ad-44cc803211ab","Cid":{"/":"QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR"},"Created":"2020-10-07T13:58:24.420077464Z","Hot":{"Enabled":false,"Size":0,"Ipfs":{"Created":"0001-01-01T00:00:00Z"}},"Cold":{"Enabled":true,"Filecoin":{"DataCid":{"/":"QmbtfAvVRVgEa9RH6vYpKg1HWbBQjxiZ6vNG1AAvt3vyfR"},"Size":33554432,"Proposals":[{"ProposalCid":{"/":"bafyreibncqapiwyvattftvfprmp74vmu47t5jycyvs7ktkejok57dv4maa"},"PieceCid":{"/":"baga6ea4seaqaneh2acoyumk6krvkatezejopmpftygl6ducgrkl7qz7vnrlx2ni"},"Renewed":false,"Duration":519572,"ActivationEpoch":124667,"StartEpoch":132466,"Miner":"t018780","EpochPrice":3125000},{"ProposalCid":{"/":"bafyreigtuke24ml7lsf276676yubcwzswfifgveiaq4l5bvwbgwvofusze"},"PieceCid":{"/":"baga6ea4seaqaneh2acoyumk6krvkatezejopmpftygl6ducgrkl7qz7vnrlx2ni"},"Renewed":false,"Duration":520884,"ActivationEpoch":125745,"StartEpoch":132466,"Miner":"t022352","EpochPrice":3125000000}]}}} +/ffs/scheduler/cistore/QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M,{"JobID":"35a6f8fc-cad5-41f4-a410-e5c3d882f0e0","Cid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"Created":"2020-10-20T12:29:12.996702455Z","Hot":{"Enabled":false,"Size":0,"Ipfs":{"Created":"0001-01-01T00:00:00Z"}},"Cold":{"Enabled":true,"Filecoin":{"DataCid":{"/":"QmZTMaDfCMWqhUXYDnKup8ctCTyPxnriYW7G4JR8KXoX5M"},"Size":67108864,"Proposals":[{"ProposalCid":{"/":"bafyreicnwrz4urwfcx3mjrjbglzg4vtjdppcp4ndtbxe35caj3gpzvo7uy"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":521469,"ActivationEpoch":162176,"StartEpoch":168927,"Miner":"f010507","EpochPrice":6250000000},{"ProposalCid":{"/":"bafyreidphishjy4vik3pd43qwspy2pal54z52g7yq5djnp5knolboziyfm"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":519893,"ActivationEpoch":163000,"StartEpoch":168927,"Miner":"f022142","EpochPrice":12500000},{"ProposalCid":{"/":"bafyreibfktn5urhqyhbmoxsnvmjgxmwhmlvs3gjnwsfst4vt7yy5myzj2u"},"PieceCid":{"/":"baga6ea4seaqhvlh3ktd4rxnbozupun776lu4wh6bprrcr6t63ec2fvkkwatn4oi"},"Renewed":false,"Duration":520113,"ActivationEpoch":145542,"StartEpoch":149621,"Miner":"f03491","EpochPrice":6250000000}]}}} diff --git a/migration/testdata/v1_Trackstore.post b/migration/testdata/v1_Trackstore.post new file mode 100644 index 000000000..de6600795 --- /dev/null +++ b/migration/testdata/v1_Trackstore.post @@ -0,0 +1,5 @@ +/ffs/scheduler/tstore/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,[{"IID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","StorageConfig":{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":300}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":8,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true}},{"IID":"fb79f525-a3c4-47f0-94e5-e344c5b1dec5","StorageConfig":{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":400}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":9,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true}}] +/ffs/scheduler/tstore/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,[{"IID":"2bef4790-a47a-4a48-90da-a89f93ab6310","StorageConfig":{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true}}] +/ffs/manager/api/ad2f3b0c-e356-43d4-a483-fba79479d7e4/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":300}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":8,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/fb79f525-a3c4-47f0-94e5-e344c5b1dec5/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":400}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":9,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/2bef4790-a47a-4a48-90da-a89f93ab6310/istore/cidstorageconfig/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} diff --git a/migration/testdata/v1_Trackstore.pre b/migration/testdata/v1_Trackstore.pre new file mode 100644 index 000000000..55552ee75 --- /dev/null +++ b/migration/testdata/v1_Trackstore.pre @@ -0,0 +1,5 @@ +/ffs/scheduler/tstore/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"IID":"ad2f3b0c-e356-43d4-a483-fba79479d7e4","StorageConfig":{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":300}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":8,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/scheduler/tstore/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,{"IID":"2bef4790-a47a-4a48-90da-a89f93ab6310","StorageConfig":{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true}} +/ffs/manager/api/ad2f3b0c-e356-43d4-a483-fba79479d7e4/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":300}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":8,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/fb79f525-a3c4-47f0-94e5-e344c5b1dec5/istore/cidstorageconfig/QmY7gN6AfKSoR7DNEjcUyXRYS85giD1YXN62cWVzS5zfus,{"Hot":{"Enabled":true,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":400}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":9,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} +/ffs/manager/api/2bef4790-a47a-4a48-90da-a89f93ab6310/istore/cidstorageconfig/QmX5J6NujFycQyoMvHXjTNmtvqDnn8TN6wAVQJ4Ap2GMnq,{"Hot":{"Enabled":false,"AllowUnfreeze":true,"UnfreezeMaxPrice":50000000,"Ipfs":{"AddTimeout":30}},"Cold":{"Enabled":true,"Filecoin":{"RepFactor":7,"DealMinDuration":518400,"ExcludedMiners":null,"TrustedMiners":null,"CountryCodes":null,"Renew":{"Enabled":false,"Threshold":0},"Addr":"t3taeln7s4dwgr42kvrajoqxuu3kfmh4vdf23xadnkjsxf2m5bnkof7shktll3es4sviytidzcmo572ibg4uvq","MaxPrice":500000000,"FastRetrieval":true,"DealStartOffset":8640}},"Repairable":true} diff --git a/proto/powergate/admin/v1/admin.proto b/proto/powergate/admin/v1/admin.proto index affacd11a..298e5cffd 100644 --- a/proto/powergate/admin/v1/admin.proto +++ b/proto/powergate/admin/v1/admin.proto @@ -94,6 +94,7 @@ message StorageJobsSummaryRequest { repeated string cids = 2; } + message StorageJobsSummaryResponse { powergate.user.v1.JobCounts job_counts = 1; repeated powergate.user.v1.StorageJob queued_storage_jobs = 2; @@ -102,6 +103,31 @@ message StorageJobsSummaryResponse { repeated powergate.user.v1.StorageJob latest_successful_storage_jobs = 5; } +message GCStagedRequest { +} + +message GCStagedResponse { + repeated string unpinned_cids = 1; +} + +message PinnedCidsRequest { +} + +message PinnedCidsResponse { + repeated HSPinnedCid cids = 1; +} + +message HSPinnedCid { + string cid = 1; + repeated HSPinnedCidUser users = 2; +} + +message HSPinnedCidUser { + string user_id = 1; + bool staged = 2; + int64 created_at = 3; +} + service AdminService { // Wallet rpc NewAddress(NewAddressRequest) returns (NewAddressResponse) {} @@ -118,4 +144,6 @@ service AdminService { rpc LatestFinalStorageJobs(LatestFinalStorageJobsRequest) returns (LatestFinalStorageJobsResponse) {} rpc LatestSuccessfulStorageJobs(LatestSuccessfulStorageJobsRequest) returns (LatestSuccessfulStorageJobsResponse) {} rpc StorageJobsSummary(StorageJobsSummaryRequest) returns (StorageJobsSummaryResponse) {} -} \ No newline at end of file + rpc GCStaged(GCStagedRequest) returns (GCStagedResponse) {} + rpc PinnedCids(PinnedCidsRequest) returns (PinnedCidsResponse) {} +} diff --git a/proto/powergate/user/v1/user.proto b/proto/powergate/user/v1/user.proto index cb5b9ca43..4b6614847 100644 --- a/proto/powergate/user/v1/user.proto +++ b/proto/powergate/user/v1/user.proto @@ -46,6 +46,13 @@ message StageResponse { string cid = 1; } +message StageCidRequest { + string cid = 1; +} + +message StageCidResponse { +} + message ApplyStorageConfigRequest { string cid = 1; StorageConfig config = 2; @@ -264,6 +271,7 @@ service UserService { // Data rpc Stage(stream StageRequest) returns (StageResponse) {} + rpc StageCid(StageCidRequest) returns (StageCidResponse) {} rpc ReplaceData(ReplaceDataRequest) returns (ReplaceDataResponse) {} rpc Get(GetRequest) returns (stream GetResponse) {} rpc WatchLogs(WatchLogsRequest) returns (stream WatchLogsResponse){} @@ -496,4 +504,4 @@ message RetrievalDealRecord { string address = 1; int64 time = 2; RetrievalDealInfo deal_info = 3; -} \ No newline at end of file +}