diff --git a/command/main.go b/command/main.go index 7b276e703b..a2e5a629a7 100644 --- a/command/main.go +++ b/command/main.go @@ -119,6 +119,11 @@ func commands() map[string]cli.CommandFactory { Meta2: meta2, }, nil }, + "status": func() (cli.Command, error) { + return &StatusCommand{ + Meta2: meta2, + }, nil + }, } } diff --git a/command/peers.go b/command/peers.go index bfe56842d9..4b99288aee 100644 --- a/command/peers.go +++ b/command/peers.go @@ -17,11 +17,11 @@ func (c *PeersCommand) Help() string { List the connected peers: - $ bor account new + $ bor peers list Add a new peer by enode: - $ bor account import + $ bor peers add Remove a connected peer by enode: diff --git a/command/peers_list.go b/command/peers_list.go index 47e9e4caf0..af0bc410fa 100644 --- a/command/peers_list.go +++ b/command/peers_list.go @@ -18,7 +18,7 @@ type PeersListCommand struct { func (p *PeersListCommand) Help() string { return `Usage: bor peers list - Build an archive containing Bor pprof traces + Lists the connected peers ` + p.Flags().Help() } diff --git a/command/server/proto/server.pb.go b/command/server/proto/server.pb.go index ab6c06662b..8f34379c9b 100644 --- a/command/server/proto/server.pb.go +++ b/command/server/proto/server.pb.go @@ -8,6 +8,7 @@ package proto import ( proto "github.com/golang/protobuf/proto" + empty "github.com/golang/protobuf/ptypes/empty" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -71,7 +72,7 @@ func (x PprofRequest_Type) Number() protoreflect.EnumNumber { // Deprecated: Use PprofRequest_Type.Descriptor instead. func (PprofRequest_Type) EnumDescriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{11, 0} + return file_command_server_proto_server_proto_rawDescGZIP(), []int{13, 0} } type PeersAddRequest struct { @@ -619,6 +620,140 @@ func (*ChainSetHeadResponse) Descriptor() ([]byte, []int) { return file_command_server_proto_server_proto_rawDescGZIP(), []int{10} } +type StatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CurrentBlock *Header `protobuf:"bytes,1,opt,name=currentBlock,proto3" json:"currentBlock,omitempty"` + CurrentHeader *Header `protobuf:"bytes,2,opt,name=currentHeader,proto3" json:"currentHeader,omitempty"` + NumPeers int64 `protobuf:"varint,3,opt,name=numPeers,proto3" json:"numPeers,omitempty"` + SyncMode string `protobuf:"bytes,4,opt,name=syncMode,proto3" json:"syncMode,omitempty"` + Syncing *StatusResponse_Syncing `protobuf:"bytes,5,opt,name=syncing,proto3" json:"syncing,omitempty"` +} + +func (x *StatusResponse) Reset() { + *x = StatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_command_server_proto_server_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusResponse) ProtoMessage() {} + +func (x *StatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_command_server_proto_server_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 StatusResponse.ProtoReflect.Descriptor instead. +func (*StatusResponse) Descriptor() ([]byte, []int) { + return file_command_server_proto_server_proto_rawDescGZIP(), []int{11} +} + +func (x *StatusResponse) GetCurrentBlock() *Header { + if x != nil { + return x.CurrentBlock + } + return nil +} + +func (x *StatusResponse) GetCurrentHeader() *Header { + if x != nil { + return x.CurrentHeader + } + return nil +} + +func (x *StatusResponse) GetNumPeers() int64 { + if x != nil { + return x.NumPeers + } + return 0 +} + +func (x *StatusResponse) GetSyncMode() string { + if x != nil { + return x.SyncMode + } + return "" +} + +func (x *StatusResponse) GetSyncing() *StatusResponse_Syncing { + if x != nil { + return x.Syncing + } + return nil +} + +type Header struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Number uint64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"` +} + +func (x *Header) Reset() { + *x = Header{} + if protoimpl.UnsafeEnabled { + mi := &file_command_server_proto_server_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Header) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Header) ProtoMessage() {} + +func (x *Header) ProtoReflect() protoreflect.Message { + mi := &file_command_server_proto_server_proto_msgTypes[12] + 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 Header.ProtoReflect.Descriptor instead. +func (*Header) Descriptor() ([]byte, []int) { + return file_command_server_proto_server_proto_rawDescGZIP(), []int{12} +} + +func (x *Header) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *Header) GetNumber() uint64 { + if x != nil { + return x.Number + } + return 0 +} + type PprofRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -632,7 +767,7 @@ type PprofRequest struct { func (x *PprofRequest) Reset() { *x = PprofRequest{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[11] + mi := &file_command_server_proto_server_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -645,7 +780,7 @@ func (x *PprofRequest) String() string { func (*PprofRequest) ProtoMessage() {} func (x *PprofRequest) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[11] + mi := &file_command_server_proto_server_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -658,7 +793,7 @@ func (x *PprofRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PprofRequest.ProtoReflect.Descriptor instead. func (*PprofRequest) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{11} + return file_command_server_proto_server_proto_rawDescGZIP(), []int{13} } func (x *PprofRequest) GetType() PprofRequest_Type { @@ -694,7 +829,7 @@ type PprofResponse struct { func (x *PprofResponse) Reset() { *x = PprofResponse{} if protoimpl.UnsafeEnabled { - mi := &file_command_server_proto_server_proto_msgTypes[12] + mi := &file_command_server_proto_server_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -707,7 +842,7 @@ func (x *PprofResponse) String() string { func (*PprofResponse) ProtoMessage() {} func (x *PprofResponse) ProtoReflect() protoreflect.Message { - mi := &file_command_server_proto_server_proto_msgTypes[12] + mi := &file_command_server_proto_server_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -720,7 +855,7 @@ func (x *PprofResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PprofResponse.ProtoReflect.Descriptor instead. func (*PprofResponse) Descriptor() ([]byte, []int) { - return file_command_server_proto_server_proto_rawDescGZIP(), []int{12} + return file_command_server_proto_server_proto_rawDescGZIP(), []int{14} } func (x *PprofResponse) GetPayload() string { @@ -737,95 +872,189 @@ func (x *PprofResponse) GetHeaders() map[string]string { return nil } +type StatusResponse_Syncing struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StartingBlock int64 `protobuf:"varint,1,opt,name=startingBlock,proto3" json:"startingBlock,omitempty"` + HighestBlock int64 `protobuf:"varint,2,opt,name=highestBlock,proto3" json:"highestBlock,omitempty"` + CurrentBlock int64 `protobuf:"varint,3,opt,name=currentBlock,proto3" json:"currentBlock,omitempty"` +} + +func (x *StatusResponse_Syncing) Reset() { + *x = StatusResponse_Syncing{} + if protoimpl.UnsafeEnabled { + mi := &file_command_server_proto_server_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusResponse_Syncing) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusResponse_Syncing) ProtoMessage() {} + +func (x *StatusResponse_Syncing) ProtoReflect() protoreflect.Message { + mi := &file_command_server_proto_server_proto_msgTypes[15] + 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 StatusResponse_Syncing.ProtoReflect.Descriptor instead. +func (*StatusResponse_Syncing) Descriptor() ([]byte, []int) { + return file_command_server_proto_server_proto_rawDescGZIP(), []int{11, 0} +} + +func (x *StatusResponse_Syncing) GetStartingBlock() int64 { + if x != nil { + return x.StartingBlock + } + return 0 +} + +func (x *StatusResponse_Syncing) GetHighestBlock() int64 { + if x != nil { + return x.HighestBlock + } + return 0 +} + +func (x *StatusResponse_Syncing) GetCurrentBlock() int64 { + if x != nil { + return x.CurrentBlock + } + return 0 +} + var File_command_server_proto_server_proto protoreflect.FileDescriptor var file_command_server_proto_server_proto_rawDesc = []byte{ 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x0f, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, + 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x0f, 0x50, 0x65, 0x65, 0x72, 0x73, + 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x50, 0x65, + 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, + 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x36, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, + 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x73, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, - 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x12, 0x0a, - 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x44, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, - 0x0a, 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x36, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, - 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x12, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x36, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, - 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x22, 0x98, - 0x01, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x65, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x12, - 0x12, 0x0a, 0x04, 0x63, 0x61, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, - 0x61, 0x70, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, - 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, - 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x22, 0x2d, 0x0a, 0x13, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x98, 0x01, 0x0a, 0x0c, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, - 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, - 0x6e, 0x64, 0x73, 0x22, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4c, - 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x10, 0x01, - 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x02, 0x22, 0xa2, 0x01, 0x0a, 0x0d, - 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3b, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x32, 0x8b, 0x03, 0x0a, 0x03, 0x42, 0x6f, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x50, 0x70, 0x72, 0x6f, - 0x66, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, - 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3e, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, - 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x17, - 0x5a, 0x15, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x64, 0x65, 0x22, 0x36, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x70, 0x65, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, 0x04, + 0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x63, 0x61, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x61, 0x70, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x22, 0x2d, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, + 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe2, 0x02, + 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x31, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x12, 0x33, 0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x4d, 0x6f, 0x64, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x37, 0x0a, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, + 0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x1a, 0x77, 0x0a, 0x07, 0x53, 0x79, 0x6e, + 0x63, 0x69, 0x6e, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x69, + 0x67, 0x68, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0c, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x22, + 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x22, 0x34, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, 0x0c, 0x50, 0x70, 0x72, + 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x26, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x10, 0x00, 0x12, + 0x07, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, + 0x45, 0x10, 0x02, 0x22, 0xa2, 0x01, 0x0a, 0x0d, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, + 0x3b, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xc4, 0x03, 0x0a, 0x03, 0x42, 0x6f, 0x72, + 0x12, 0x32, 0x0a, 0x05, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, + 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x73, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, + 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, + 0x0c, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x17, 0x5a, 0x15, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -841,46 +1070,55 @@ func file_command_server_proto_server_proto_rawDescGZIP() []byte { } var file_command_server_proto_server_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_command_server_proto_server_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_command_server_proto_server_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_command_server_proto_server_proto_goTypes = []interface{}{ - (PprofRequest_Type)(0), // 0: proto.PprofRequest.Type - (*PeersAddRequest)(nil), // 1: proto.PeersAddRequest - (*PeersAddResponse)(nil), // 2: proto.PeersAddResponse - (*PeersRemoveRequest)(nil), // 3: proto.PeersRemoveRequest - (*PeersRemoveResponse)(nil), // 4: proto.PeersRemoveResponse - (*PeersListRequest)(nil), // 5: proto.PeersListRequest - (*PeersListResponse)(nil), // 6: proto.PeersListResponse - (*PeersStatusRequest)(nil), // 7: proto.PeersStatusRequest - (*PeersStatusResponse)(nil), // 8: proto.PeersStatusResponse - (*Peer)(nil), // 9: proto.Peer - (*ChainSetHeadRequest)(nil), // 10: proto.ChainSetHeadRequest - (*ChainSetHeadResponse)(nil), // 11: proto.ChainSetHeadResponse - (*PprofRequest)(nil), // 12: proto.PprofRequest - (*PprofResponse)(nil), // 13: proto.PprofResponse - nil, // 14: proto.PprofResponse.HeadersEntry + (PprofRequest_Type)(0), // 0: proto.PprofRequest.Type + (*PeersAddRequest)(nil), // 1: proto.PeersAddRequest + (*PeersAddResponse)(nil), // 2: proto.PeersAddResponse + (*PeersRemoveRequest)(nil), // 3: proto.PeersRemoveRequest + (*PeersRemoveResponse)(nil), // 4: proto.PeersRemoveResponse + (*PeersListRequest)(nil), // 5: proto.PeersListRequest + (*PeersListResponse)(nil), // 6: proto.PeersListResponse + (*PeersStatusRequest)(nil), // 7: proto.PeersStatusRequest + (*PeersStatusResponse)(nil), // 8: proto.PeersStatusResponse + (*Peer)(nil), // 9: proto.Peer + (*ChainSetHeadRequest)(nil), // 10: proto.ChainSetHeadRequest + (*ChainSetHeadResponse)(nil), // 11: proto.ChainSetHeadResponse + (*StatusResponse)(nil), // 12: proto.StatusResponse + (*Header)(nil), // 13: proto.Header + (*PprofRequest)(nil), // 14: proto.PprofRequest + (*PprofResponse)(nil), // 15: proto.PprofResponse + (*StatusResponse_Syncing)(nil), // 16: proto.StatusResponse.Syncing + nil, // 17: proto.PprofResponse.HeadersEntry + (*empty.Empty)(nil), // 18: google.protobuf.Empty } var file_command_server_proto_server_proto_depIdxs = []int32{ 9, // 0: proto.PeersListResponse.peers:type_name -> proto.Peer 9, // 1: proto.PeersStatusResponse.peer:type_name -> proto.Peer - 0, // 2: proto.PprofRequest.type:type_name -> proto.PprofRequest.Type - 14, // 3: proto.PprofResponse.headers:type_name -> proto.PprofResponse.HeadersEntry - 12, // 4: proto.Bor.Pprof:input_type -> proto.PprofRequest - 1, // 5: proto.Bor.PeersAdd:input_type -> proto.PeersAddRequest - 3, // 6: proto.Bor.PeersRemove:input_type -> proto.PeersRemoveRequest - 5, // 7: proto.Bor.PeersList:input_type -> proto.PeersListRequest - 7, // 8: proto.Bor.PeersStatus:input_type -> proto.PeersStatusRequest - 10, // 9: proto.Bor.ChainSetHead:input_type -> proto.ChainSetHeadRequest - 13, // 10: proto.Bor.Pprof:output_type -> proto.PprofResponse - 2, // 11: proto.Bor.PeersAdd:output_type -> proto.PeersAddResponse - 4, // 12: proto.Bor.PeersRemove:output_type -> proto.PeersRemoveResponse - 6, // 13: proto.Bor.PeersList:output_type -> proto.PeersListResponse - 8, // 14: proto.Bor.PeersStatus:output_type -> proto.PeersStatusResponse - 11, // 15: proto.Bor.ChainSetHead:output_type -> proto.ChainSetHeadResponse - 10, // [10:16] is the sub-list for method output_type - 4, // [4:10] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 13, // 2: proto.StatusResponse.currentBlock:type_name -> proto.Header + 13, // 3: proto.StatusResponse.currentHeader:type_name -> proto.Header + 16, // 4: proto.StatusResponse.syncing:type_name -> proto.StatusResponse.Syncing + 0, // 5: proto.PprofRequest.type:type_name -> proto.PprofRequest.Type + 17, // 6: proto.PprofResponse.headers:type_name -> proto.PprofResponse.HeadersEntry + 14, // 7: proto.Bor.Pprof:input_type -> proto.PprofRequest + 1, // 8: proto.Bor.PeersAdd:input_type -> proto.PeersAddRequest + 3, // 9: proto.Bor.PeersRemove:input_type -> proto.PeersRemoveRequest + 5, // 10: proto.Bor.PeersList:input_type -> proto.PeersListRequest + 7, // 11: proto.Bor.PeersStatus:input_type -> proto.PeersStatusRequest + 10, // 12: proto.Bor.ChainSetHead:input_type -> proto.ChainSetHeadRequest + 18, // 13: proto.Bor.Status:input_type -> google.protobuf.Empty + 15, // 14: proto.Bor.Pprof:output_type -> proto.PprofResponse + 2, // 15: proto.Bor.PeersAdd:output_type -> proto.PeersAddResponse + 4, // 16: proto.Bor.PeersRemove:output_type -> proto.PeersRemoveResponse + 6, // 17: proto.Bor.PeersList:output_type -> proto.PeersListResponse + 8, // 18: proto.Bor.PeersStatus:output_type -> proto.PeersStatusResponse + 11, // 19: proto.Bor.ChainSetHead:output_type -> proto.ChainSetHeadResponse + 12, // 20: proto.Bor.Status:output_type -> proto.StatusResponse + 14, // [14:21] is the sub-list for method output_type + 7, // [7:14] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_command_server_proto_server_proto_init() } @@ -1022,7 +1260,7 @@ func file_command_server_proto_server_proto_init() { } } file_command_server_proto_server_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PprofRequest); i { + switch v := v.(*StatusResponse); i { case 0: return &v.state case 1: @@ -1034,6 +1272,30 @@ func file_command_server_proto_server_proto_init() { } } file_command_server_proto_server_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Header); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_command_server_proto_server_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PprofRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_command_server_proto_server_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PprofResponse); i { case 0: return &v.state @@ -1045,6 +1307,18 @@ func file_command_server_proto_server_proto_init() { return nil } } + file_command_server_proto_server_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatusResponse_Syncing); 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{ @@ -1052,7 +1326,7 @@ func file_command_server_proto_server_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_command_server_proto_server_proto_rawDesc, NumEnums: 1, - NumMessages: 14, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/command/server/proto/server.proto b/command/server/proto/server.proto index 535aa3f369..26e5962aa2 100644 --- a/command/server/proto/server.proto +++ b/command/server/proto/server.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package proto; +import "google/protobuf/empty.proto"; + option go_package = "/command/server/proto"; service Bor { @@ -16,6 +18,8 @@ service Bor { rpc PeersStatus(PeersStatusRequest) returns (PeersStatusResponse); rpc ChainSetHead(ChainSetHeadRequest) returns (ChainSetHeadResponse); + + rpc Status(google.protobuf.Empty) returns (StatusResponse); } @@ -67,6 +71,25 @@ message ChainSetHeadRequest { message ChainSetHeadResponse { } +message StatusResponse { + Header currentBlock = 1; + Header currentHeader = 2; + int64 numPeers = 3; + string syncMode = 4; + Syncing syncing = 5; + + message Syncing { + int64 startingBlock = 1; + int64 highestBlock = 2; + int64 currentBlock = 3; + } +} + +message Header { + string hash = 1; + uint64 number = 2; +} + message PprofRequest { Type type = 1; diff --git a/command/server/proto/server_grpc.pb.go b/command/server/proto/server_grpc.pb.go index 369419b66f..e385a16968 100644 --- a/command/server/proto/server_grpc.pb.go +++ b/command/server/proto/server_grpc.pb.go @@ -4,6 +4,7 @@ package proto import ( context "context" + empty "github.com/golang/protobuf/ptypes/empty" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -24,6 +25,7 @@ type BorClient interface { PeersList(ctx context.Context, in *PeersListRequest, opts ...grpc.CallOption) (*PeersListResponse, error) PeersStatus(ctx context.Context, in *PeersStatusRequest, opts ...grpc.CallOption) (*PeersStatusResponse, error) ChainSetHead(ctx context.Context, in *ChainSetHeadRequest, opts ...grpc.CallOption) (*ChainSetHeadResponse, error) + Status(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*StatusResponse, error) } type borClient struct { @@ -88,6 +90,15 @@ func (c *borClient) ChainSetHead(ctx context.Context, in *ChainSetHeadRequest, o return out, nil } +func (c *borClient) Status(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*StatusResponse, error) { + out := new(StatusResponse) + err := c.cc.Invoke(ctx, "/proto.Bor/Status", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // BorServer is the server API for Bor service. // All implementations must embed UnimplementedBorServer // for forward compatibility @@ -98,6 +109,7 @@ type BorServer interface { PeersList(context.Context, *PeersListRequest) (*PeersListResponse, error) PeersStatus(context.Context, *PeersStatusRequest) (*PeersStatusResponse, error) ChainSetHead(context.Context, *ChainSetHeadRequest) (*ChainSetHeadResponse, error) + Status(context.Context, *empty.Empty) (*StatusResponse, error) mustEmbedUnimplementedBorServer() } @@ -123,6 +135,9 @@ func (UnimplementedBorServer) PeersStatus(context.Context, *PeersStatusRequest) func (UnimplementedBorServer) ChainSetHead(context.Context, *ChainSetHeadRequest) (*ChainSetHeadResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ChainSetHead not implemented") } +func (UnimplementedBorServer) Status(context.Context, *empty.Empty) (*StatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") +} func (UnimplementedBorServer) mustEmbedUnimplementedBorServer() {} // UnsafeBorServer may be embedded to opt out of forward compatibility for this service. @@ -244,6 +259,24 @@ func _Bor_ChainSetHead_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Bor_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BorServer).Status(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.Bor/Status", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BorServer).Status(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + // Bor_ServiceDesc is the grpc.ServiceDesc for Bor service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -275,6 +308,10 @@ var Bor_ServiceDesc = grpc.ServiceDesc{ MethodName: "ChainSetHead", Handler: _Bor_ChainSetHead_Handler, }, + { + MethodName: "Status", + Handler: _Bor_Status_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "command/server/proto/server.proto", diff --git a/command/server/server.go b/command/server/server.go index bab4673214..afc0550b2a 100644 --- a/command/server/server.go +++ b/command/server/server.go @@ -38,10 +38,13 @@ type Server struct { backend *eth.Ethereum grpcServer *grpc.Server tracer *sdktrace.TracerProvider + config *Config } func NewServer(config *Config) (*Server, error) { - srv := &Server{} + srv := &Server{ + config: config, + } // start the logger setupLogger(config.LogLevel) diff --git a/command/server/service.go b/command/server/service.go index 0c6c23b6bf..0ad5a145b7 100644 --- a/command/server/service.go +++ b/command/server/service.go @@ -8,8 +8,10 @@ import ( "github.com/ethereum/go-ethereum/command/server/pprof" "github.com/ethereum/go-ethereum/command/server/proto" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/golang/protobuf/ptypes/empty" ) func (s *Server) Pprof(ctx context.Context, req *proto.PprofRequest) (*proto.PprofResponse, error) { @@ -107,3 +109,28 @@ func (s *Server) ChainSetHead(ctx context.Context, req *proto.ChainSetHeadReques s.backend.APIBackend.SetHead(req.Number) return &proto.ChainSetHeadResponse{}, nil } + +func (s *Server) Status(ctx context.Context, _ *empty.Empty) (*proto.StatusResponse, error) { + apiBackend := s.backend.APIBackend + syncProgress := apiBackend.SyncProgress() + + resp := &proto.StatusResponse{ + CurrentHeader: headerToProtoHeader(apiBackend.CurrentHeader()), + CurrentBlock: headerToProtoHeader(apiBackend.CurrentBlock().Header()), + NumPeers: int64(len(s.node.Server().PeersInfo())), + SyncMode: s.config.SyncMode, + Syncing: &proto.StatusResponse_Syncing{ + StartingBlock: int64(syncProgress.StartingBlock), + HighestBlock: int64(syncProgress.HighestBlock), + CurrentBlock: int64(syncProgress.CurrentBlock), + }, + } + return resp, nil +} + +func headerToProtoHeader(h *types.Header) *proto.Header { + return &proto.Header{ + Hash: h.Hash().String(), + Number: h.Number.Uint64(), + } +} diff --git a/command/status.go b/command/status.go new file mode 100644 index 0000000000..0df849a1a4 --- /dev/null +++ b/command/status.go @@ -0,0 +1,78 @@ +package main + +import ( + "context" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/command/server/proto" + "github.com/golang/protobuf/ptypes/empty" +) + +// StatusCommand is the command to output the status of the client +type StatusCommand struct { + *Meta2 +} + +// Help implements the cli.Command interface +func (p *StatusCommand) Help() string { + return `Usage: bor status + + Output the status of the client` +} + +// Synopsis implements the cli.Command interface +func (c *StatusCommand) Synopsis() string { + return "Output the status of the client" +} + +// Run implements the cli.Command interface +func (c *StatusCommand) Run(args []string) int { + flags := c.NewFlagSet("status") + if err := flags.Parse(args); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + borClt, err := c.BorConn() + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + + status, err := borClt.Status(context.Background(), &empty.Empty{}) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + + c.UI.Output(printStatus(status)) + return 0 +} + +func printStatus(status *proto.StatusResponse) string { + printHeader := func(h *proto.Header) string { + return formatKV([]string{ + fmt.Sprintf("Hash|%s", h.Hash), + fmt.Sprintf("Number|%d", h.Number), + }) + } + full := []string{ + "General", + formatKV([]string{ + fmt.Sprintf("Num peers|%d", status.NumPeers), + fmt.Sprintf("Sync mode|%s", status.SyncMode), + }), + "\nCurrent Header", + printHeader(status.CurrentHeader), + "\nCurrent Block", + printHeader(status.CurrentBlock), + "\nSyncing", + formatKV([]string{ + fmt.Sprintf("Current block|%d", status.Syncing.CurrentBlock), + fmt.Sprintf("Highest block|%d", status.Syncing.HighestBlock), + fmt.Sprintf("Starting block|%d", status.Syncing.StartingBlock), + }), + } + return strings.Join(full, "\n") +} diff --git a/docs/cli/README.md b/docs/cli/README.md index c82bbbe047..74a6df2ca0 100644 --- a/docs/cli/README.md +++ b/docs/cli/README.md @@ -15,4 +15,20 @@ - [```account import```](./account_import.md) +- [```chain```](./chain.md) + +- [```chain sethead```](./chain_sethead.md) + +- [```peers```](./peers.md) + +- [```peers add```](./peers_add.md) + +- [```peers list```](./peers_list.md) + +- [```peers remove```](./peers_remove.md) + +- [```peers status```](./peers_status.md) + +- [```status```](./status.md) + - [```version```](./version.md) diff --git a/docs/cli/chain.md b/docs/cli/chain.md new file mode 100644 index 0000000000..e55a90f122 --- /dev/null +++ b/docs/cli/chain.md @@ -0,0 +1,6 @@ + +# Chain + +The ```chain``` command groups actions to interact with the blockchain in the client: + +- [```chain sethead```](./chain_sethead.md): Set the current chain to a certain block. diff --git a/docs/cli/chain_sethead.md b/docs/cli/chain_sethead.md new file mode 100644 index 0000000000..985383988f --- /dev/null +++ b/docs/cli/chain_sethead.md @@ -0,0 +1,12 @@ + +# Chain sethead + +The ```chain sethead ``` command sets the current chain to a certain block. + +## Arguments + +- ```number```: The block number to roll back. + +## Options + +- ```yes```: Force set head. diff --git a/docs/cli/peers.md b/docs/cli/peers.md new file mode 100644 index 0000000000..57b4889a00 --- /dev/null +++ b/docs/cli/peers.md @@ -0,0 +1,12 @@ + +# Peers + +The ```peers``` command groups actions to interact with peers: + +- [```peers add```](./peers_add.md): Joins the local client to another remote peer. + +- [```peers list```](./peers_list.md): Lists the connected peers to the Bor client. + +- [```peers remove```](./peers_remove.md): Disconnects the local client from a connected peer if exists. + +- [```peers status```](./peers_status.md): Display the status of a peer by its id. diff --git a/docs/cli/peers_add.md b/docs/cli/peers_add.md new file mode 100644 index 0000000000..35e5ece450 --- /dev/null +++ b/docs/cli/peers_add.md @@ -0,0 +1,8 @@ + +# Peers add + +The ```peers add ``` command joins the local client to another remote peer. + +## Arguments + +- ```trusted```: Whether the peer is added as a trusted peer. diff --git a/docs/cli/peers_list.md b/docs/cli/peers_list.md new file mode 100644 index 0000000000..cb1ef2f599 --- /dev/null +++ b/docs/cli/peers_list.md @@ -0,0 +1,4 @@ + +# Peers list + +The ```peers list``` command lists the connected peers. diff --git a/docs/cli/peers_remove.md b/docs/cli/peers_remove.md new file mode 100644 index 0000000000..e2fa0a71df --- /dev/null +++ b/docs/cli/peers_remove.md @@ -0,0 +1,4 @@ + +# Peers remove + +The ```peers remove ``` command disconnects the local client from a connected peer if exists. diff --git a/docs/cli/peers_status.md b/docs/cli/peers_status.md new file mode 100644 index 0000000000..56343c8d6b --- /dev/null +++ b/docs/cli/peers_status.md @@ -0,0 +1,4 @@ + +# Peers status + +The ```peers status ``` command displays the status of a peer by its id. diff --git a/docs/cli/status.md b/docs/cli/status.md new file mode 100644 index 0000000000..fb7bddb182 --- /dev/null +++ b/docs/cli/status.md @@ -0,0 +1,4 @@ + +# Status + +The ```status``` command outputs the status of the client.