diff --git a/README.md b/README.md index cca276d0..6e152ba3 100644 --- a/README.md +++ b/README.md @@ -207,17 +207,9 @@ enum SupernodeEventType { See docs/gateway.md for the full gateway guide (endpoints, examples, Swagger links). -### Codec Configuration (fixed policy) +### HTTP Gateway -The supernode uses a fixed RaptorQ codec policy (linux/amd64 only): -- Concurrency: 4 -- Symbol size: 65535 -- Redundancy: 5 -- Max memory: detected cgroup/system memory minus 10% headroom - -Status includes these effective values under `codec` in `StatusResponse`. -The HTTP gateway also exposes a minimal view at `GET /api/v1/codec` with: -- `symbol_size`, `redundancy`, `max_memory_mb`, `concurrency`, `headroom_pct`, `mem_limit_mb`, `mem_limit_source`. +See docs/gateway.md for the full gateway guide (endpoints, examples, Swagger links). ## CLI Commands diff --git a/docs/cascade-store-artifacts.md b/docs/cascade-store-artifacts.md new file mode 100644 index 00000000..880f5418 --- /dev/null +++ b/docs/cascade-store-artifacts.md @@ -0,0 +1,164 @@ +# Cascade Artefacts Storage Flow + +This document explains, in depth, how Cascade artefacts (ID files + RaptorQ symbols) are persisted to the P2P network, the control flow from the API to the P2P layer, what metrics are collected, and which background workers continue the process after the API call returns. + +## Scope & Terminology + +- Artefacts: The data produced for a Cascade action that must be stored on the network. + - ID files (a.k.a. redundant metadata files): compact metadata payloads derived from the layout/index. + - Symbols: RaptorQ-encoded chunks of the input file. +- Request IDs and files are generated during the registration flow; storing starts after validation and simulation succeed. + +## High‑Level Sequence + +1) Client calls `Register` with input file and action metadata. +2) The service verifies the action, fee, eligibility, signature and layout consistency, then encodes the input into RaptorQ symbols. +3) Finalize simulation is performed on chain to ensure the action can finalize. +4) If simulation passes, artefacts are persisted: + - ID files are stored first as a single batch. + - Symbols are stored in batches; a first pass may downsample for large directories. + - A background worker continues storing the remainder (no sampling) after the call returns. +5) Action is finalized on chain and control returns to the caller. + +Code reference: +- `supernode/services/cascade/register.go` (Register flow, steps 1–11) +- `supernode/services/cascade/helper.go` (wrappers and helpers) +- `supernode/services/cascade/adaptors/p2p.go` (P2P adaptor for storage) +- `p2p/p2p.go`, `p2p/kademlia/dht.go`, `p2p/kademlia/rq_symbols.go` (P2P and Kademlia implementation) + +## Register Flow Up To Storage + +Register performs the following (simplified): + +- Fetches and validates the on‑chain action. +- Verifies fee and that this node is in the top supernodes for the block height. +- Decodes cascade metadata and verifies that the uploaded data hash matches the ticket. +- Encodes the input using RaptorQ; produces `SymbolsDir` and `Metadata` (layout). +- Verifies layout signature (creator), generates RQ‑ID files and validates IDs. +- Simulates finalize (chain dry‑run). If simulation fails, the call returns with an error (no storage). +- Calls `storeArtefacts(...)` to persist artefacts to P2P. + +Events are streamed throughout via `send(*RegisterResponse)`, including when artefacts are stored and when the action is finalized. + +## The storeArtefacts Wrapper + +Function: `supernode/services/cascade/helper.go::storeArtefacts` + +- Thin pass‑through that packages a `StoreArtefactsRequest` and forwards to the P2P adaptor (`task.P2P.StoreArtefacts`). +- Parameters: + - `IDFiles [][]byte`: the redundant metadata files to store. + - `SymbolsDir string`: filesystem directory where symbols were written. + - `TaskID string` and `ActionID string`: identifiers for logging and DB association. + +Returns `StoreArtefactsMetrics` with separate metrics for metadata and symbols plus an aggregated view. + +## P2P Adaptor: StoreArtefacts + +Implementation: `supernode/services/cascade/adaptors/p2p.go` + +1) Store metadata (ID files) using `p2p.Client.StoreBatch(...)`: + - Returns `metaRatePct` and `metaRequests` (count of per‑node RPCs attempted during this batch store). + +2) Store symbols using `storeCascadeSymbols(...)`: + - Records the symbol directory in a small SQLite store: `rqStore.StoreSymbolDirectory(taskID, symbolsDir)`. + - Walks `symbolsDir` to list symbol files. If there are more than 2,500 symbols, downsamples to 10% for this first pass (random sample, sorted deterministically afterward). + - Streams symbols in fixed‑size batches of 2,500 files: + - Each batch loads files, calls `p2p.Client.StoreBatch(...)` with a 5‑minute timeout, and deletes successfully uploaded files. + - Marks “first batch stored” for this action: `rqStore.UpdateIsFirstBatchStored(actionID)`. + - Returns `(symRatePct, symCount, symRequests)`. + +3) Aggregation and return: + - Computes item‑weighted aggregate success rate across metadata and symbols: `aggRate = (metaRate*metaCount + symRate*symCount) / (metaCount + symCount)`. + - Total requests = `metaRequests + symRequests`. + - Returns `StoreArtefactsMetrics` with all fields populated. + +Notes: +- This adaptor only performs a first pass of symbol storage. For large directories it may downsample; the background worker completes the remaining symbols later (see Background Worker section). + +## P2P Client and DHT: StoreBatch + +`p2p.Client.StoreBatch` proxies to `DHT.StoreBatch`: + +- Local persist first: `store.StoreBatch(ctx, values, typ, true)` ensures local DB/storage contains the items. +- Network store: `DHT.IterateBatchStore(ctx, values, typ, taskID)`: + - For each value, compute its Blake3 hash; compute the top‑K closest nodes from the routing table. + - Build a node→items map and invoke `batchStoreNetwork(...)` with bounded concurrency (a goroutine per node, limited via a semaphore; all joined before returning). + - Tally per‑node RPC attempts (requests) and successes to compute `successRatePct`. + - If the measured rate is below `minimumDataStoreSuccessRate` (75%), return an error along with `(ratePct, requests)`. + - Otherwise, return `(ratePct, requests, nil)`. + +Important distinctions: +- `requests` is the number of per‑node RPCs attempted; it is not the number of items in the batch. +- Success rate is based on successful node acknowledgements divided by `requests`. + +## Metrics & Events + +Returned metrics (from `StoreArtefacts`): + +- Metadata: `MetaRate` (%), `MetaRequests`, `MetaCount`. +- Symbols: `SymRate` (%), `SymRequests`, `SymCount`. +- Aggregate: `AggregatedRate` (item‑weighted), `TotalRequests`. + +`Register` logs and emits a single event line summarizing these metrics via `emitArtefactsStored(...)`, then proceeds to finalize the action on chain. + +## Background Worker (Symbols Continuation) + +Started in DHT `run()` when P2P service starts: + +- Function: `p2p/kademlia/rq_symbols.go::startStoreSymbolsWorker` +- Every 30 seconds: + - Queries `rq_symbols_dir` for rows where `is_first_batch_stored = TRUE` and `is_completed = FALSE`. + - For each directory, scans and stores ALL remaining symbols (no sampling) in 1,000‑file batches using the same `StoreBatch` API. + - Deletes files after successful upload. + - Marks the directory as completed: `rqstore.SetIsCompleted(txid)`. + +Effectively, the API call performs a first pass, and the background worker ensures eventual completion. + +## Storage Bookkeeping (SQLite) + +Table: `rq_symbols_dir` + +- Columns: + - `txid TEXT PRIMARY KEY` — action/task identifier. + - `dir TEXT NOT NULL` — filesystem path to the symbols directory. + - `is_first_batch_stored BOOLEAN NOT NULL DEFAULT FALSE` — set true after first pass completes. + - `is_completed BOOLEAN NOT NULL DEFAULT FALSE` — set true after the background worker completes. + - `created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP`. + +APIs: +- `StoreSymbolDirectory(txid, dir)` — insert entry when first pass starts. +- `UpdateIsFirstBatchStored(txid)` — mark first pass completion. +- `GetToDoStoreSymbolDirs()` — list txids/dirs awaiting background completion. +- `SetIsCompleted(txid)` — mark directory as fully processed. + +## Timeouts, Limits, and Knobs + +- First‑pass symbol batches: 2,500 items; per‑batch timeout: 5 minutes. +- Sampling threshold: if symbol count > 2,500, downsample to 10% for first pass. +- DHT minimum success rate: 75% — batch returns error if not met. +- Background worker batch size: 1,000; runs every 30 seconds; no sampling. + +These values can be tuned in: +- `supernode/services/cascade/adaptors/p2p.go` (batching, sampling for first pass). +- `p2p/kademlia/rq_symbols.go` (background worker interval and batch size). +- `p2p/kademlia/dht.go` (minimum success rate, internal concurrencies). + +## Error Handling & Return Semantics + +- If finalize simulation fails: Register returns an error before any storage. +- If metadata store fails: `StoreArtefacts` returns error; Register wraps and returns. +- If symbol first pass fails: same; background worker does not start because `is_first_batch_stored` is not set. +- If the network success rate is below the threshold: DHT returns an error; adaptor propagates it. +- File I/O errors (load/delete) abort the corresponding batch with a wrapped error. + +## Concurrency Model + +- Within `StoreArtefacts` → `DHT.StoreBatch`, network calls are concurrent (goroutines per node) but **joined before return**. There is no detached goroutine in the first pass. +- The only long‑running background activity is the P2P‑level worker (`startStoreSymbolsWorker`) launched when the P2P service starts, not by the API call itself. + +## Cleanup Behavior + +- First pass deletes uploaded symbol files per batch (`utils.DeleteSymbols`) after a successful store batch. +- Background worker also deletes files after each batch store. +- The uploaded raw input file is removed by `Register` in a `defer` block regardless of outcome. + diff --git a/docs/gateway.md b/docs/gateway.md index 19c43447..58814f5e 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -22,20 +22,6 @@ curl "http://localhost:8002/api/v1/status?include_p2p_metrics=true" Example responses are shown in the main README under the SupernodeService section. -### GET `/api/v1/codec` -Returns the minimal effective RaptorQ codec configuration used by the node (fixed policy): - -```json -{ - "symbol_size": 65535, - "redundancy": 5, - "max_memory_mb": 12288, - "concurrency": 4, - "headroom_pct": 10, - "mem_limit_mb": 13653, - "mem_limit_source": "cgroupv2:memory.max" -} -``` ## API Documentation diff --git a/gen/supernode/supernode.pb.go b/gen/supernode/supernode.pb.go index 966573dd..5410f5c6 100644 --- a/gen/supernode/supernode.pb.go +++ b/gen/supernode/supernode.pb.go @@ -7,11 +7,12 @@ package supernode import ( + reflect "reflect" + sync "sync" + _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" ) const ( @@ -225,7 +226,6 @@ type StatusResponse struct { Rank int32 `protobuf:"varint,7,opt,name=rank,proto3" json:"rank,omitempty"` // Rank in the top supernodes list (0 if not in top list) IpAddress string `protobuf:"bytes,8,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` // Supernode IP address with port (e.g., "192.168.1.1:4445") P2PMetrics *StatusResponse_P2PMetrics `protobuf:"bytes,9,opt,name=p2p_metrics,json=p2pMetrics,proto3" json:"p2p_metrics,omitempty"` - Codec *StatusResponse_CodecConfig `protobuf:"bytes,10,opt,name=codec,proto3" json:"codec,omitempty"` } func (x *StatusResponse) Reset() { @@ -321,13 +321,6 @@ func (x *StatusResponse) GetP2PMetrics() *StatusResponse_P2PMetrics { return nil } -func (x *StatusResponse) GetCodec() *StatusResponse_CodecConfig { - if x != nil { - return x.Codec - } - return nil -} - // System resource information type StatusResponse_Resources struct { state protoimpl.MessageState @@ -600,100 +593,6 @@ func (x *StatusResponse_P2PMetrics) GetDisk() *StatusResponse_P2PMetrics_DiskSta return nil } -// RaptorQ codec configuration (effective values) -type StatusResponse_CodecConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SymbolSize uint32 `protobuf:"varint,1,opt,name=symbol_size,json=symbolSize,proto3" json:"symbol_size,omitempty"` // bytes (typically 65535) - Redundancy uint32 `protobuf:"varint,2,opt,name=redundancy,proto3" json:"redundancy,omitempty"` // repair factor (percent-like scalar; 5 = default) - MaxMemoryMb uint64 `protobuf:"varint,3,opt,name=max_memory_mb,json=maxMemoryMb,proto3" json:"max_memory_mb,omitempty"` // memory cap for native decoder - Concurrency uint32 `protobuf:"varint,4,opt,name=concurrency,proto3" json:"concurrency,omitempty"` // native decoder parallelism - HeadroomPct int32 `protobuf:"varint,6,opt,name=headroom_pct,json=headroomPct,proto3" json:"headroom_pct,omitempty"` // reserved memory percentage (0-90) - MemLimitMb uint64 `protobuf:"varint,7,opt,name=mem_limit_mb,json=memLimitMb,proto3" json:"mem_limit_mb,omitempty"` // detected memory limit (MB) - MemLimitSource string `protobuf:"bytes,8,opt,name=mem_limit_source,json=memLimitSource,proto3" json:"mem_limit_source,omitempty"` // detection source (cgroup/meminfo) -} - -func (x *StatusResponse_CodecConfig) Reset() { - *x = StatusResponse_CodecConfig{} - mi := &file_supernode_supernode_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *StatusResponse_CodecConfig) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StatusResponse_CodecConfig) ProtoMessage() {} - -func (x *StatusResponse_CodecConfig) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[9] - if 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_CodecConfig.ProtoReflect.Descriptor instead. -func (*StatusResponse_CodecConfig) Descriptor() ([]byte, []int) { - return file_supernode_supernode_proto_rawDescGZIP(), []int{4, 4} -} - -func (x *StatusResponse_CodecConfig) GetSymbolSize() uint32 { - if x != nil { - return x.SymbolSize - } - return 0 -} - -func (x *StatusResponse_CodecConfig) GetRedundancy() uint32 { - if x != nil { - return x.Redundancy - } - return 0 -} - -func (x *StatusResponse_CodecConfig) GetMaxMemoryMb() uint64 { - if x != nil { - return x.MaxMemoryMb - } - return 0 -} - -func (x *StatusResponse_CodecConfig) GetConcurrency() uint32 { - if x != nil { - return x.Concurrency - } - return 0 -} - -func (x *StatusResponse_CodecConfig) GetHeadroomPct() int32 { - if x != nil { - return x.HeadroomPct - } - return 0 -} - -func (x *StatusResponse_CodecConfig) GetMemLimitMb() uint64 { - if x != nil { - return x.MemLimitMb - } - return 0 -} - -func (x *StatusResponse_CodecConfig) GetMemLimitSource() string { - if x != nil { - return x.MemLimitSource - } - return "" -} - type StatusResponse_Resources_CPU struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -705,7 +604,7 @@ type StatusResponse_Resources_CPU struct { func (x *StatusResponse_Resources_CPU) Reset() { *x = StatusResponse_Resources_CPU{} - mi := &file_supernode_supernode_proto_msgTypes[10] + mi := &file_supernode_supernode_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -717,7 +616,7 @@ func (x *StatusResponse_Resources_CPU) String() string { func (*StatusResponse_Resources_CPU) ProtoMessage() {} func (x *StatusResponse_Resources_CPU) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[10] + mi := &file_supernode_supernode_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -760,7 +659,7 @@ type StatusResponse_Resources_Memory struct { func (x *StatusResponse_Resources_Memory) Reset() { *x = StatusResponse_Resources_Memory{} - mi := &file_supernode_supernode_proto_msgTypes[11] + mi := &file_supernode_supernode_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -772,7 +671,7 @@ func (x *StatusResponse_Resources_Memory) String() string { func (*StatusResponse_Resources_Memory) ProtoMessage() {} func (x *StatusResponse_Resources_Memory) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[11] + mi := &file_supernode_supernode_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -830,7 +729,7 @@ type StatusResponse_Resources_Storage struct { func (x *StatusResponse_Resources_Storage) Reset() { *x = StatusResponse_Resources_Storage{} - mi := &file_supernode_supernode_proto_msgTypes[12] + mi := &file_supernode_supernode_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -842,7 +741,7 @@ func (x *StatusResponse_Resources_Storage) String() string { func (*StatusResponse_Resources_Storage) ProtoMessage() {} func (x *StatusResponse_Resources_Storage) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[12] + mi := &file_supernode_supernode_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -907,7 +806,7 @@ type StatusResponse_P2PMetrics_DhtMetrics struct { func (x *StatusResponse_P2PMetrics_DhtMetrics) Reset() { *x = StatusResponse_P2PMetrics_DhtMetrics{} - mi := &file_supernode_supernode_proto_msgTypes[13] + mi := &file_supernode_supernode_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -919,7 +818,7 @@ func (x *StatusResponse_P2PMetrics_DhtMetrics) String() string { func (*StatusResponse_P2PMetrics_DhtMetrics) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_DhtMetrics) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[13] + mi := &file_supernode_supernode_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -977,7 +876,7 @@ type StatusResponse_P2PMetrics_HandleCounters struct { func (x *StatusResponse_P2PMetrics_HandleCounters) Reset() { *x = StatusResponse_P2PMetrics_HandleCounters{} - mi := &file_supernode_supernode_proto_msgTypes[14] + mi := &file_supernode_supernode_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -989,7 +888,7 @@ func (x *StatusResponse_P2PMetrics_HandleCounters) String() string { func (*StatusResponse_P2PMetrics_HandleCounters) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_HandleCounters) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[14] + mi := &file_supernode_supernode_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1049,7 +948,7 @@ type StatusResponse_P2PMetrics_BanEntry struct { func (x *StatusResponse_P2PMetrics_BanEntry) Reset() { *x = StatusResponse_P2PMetrics_BanEntry{} - mi := &file_supernode_supernode_proto_msgTypes[15] + mi := &file_supernode_supernode_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1061,7 +960,7 @@ func (x *StatusResponse_P2PMetrics_BanEntry) String() string { func (*StatusResponse_P2PMetrics_BanEntry) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_BanEntry) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[15] + mi := &file_supernode_supernode_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1131,7 +1030,7 @@ type StatusResponse_P2PMetrics_DatabaseStats struct { func (x *StatusResponse_P2PMetrics_DatabaseStats) Reset() { *x = StatusResponse_P2PMetrics_DatabaseStats{} - mi := &file_supernode_supernode_proto_msgTypes[16] + mi := &file_supernode_supernode_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1143,7 +1042,7 @@ func (x *StatusResponse_P2PMetrics_DatabaseStats) String() string { func (*StatusResponse_P2PMetrics_DatabaseStats) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_DatabaseStats) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[16] + mi := &file_supernode_supernode_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1186,7 +1085,7 @@ type StatusResponse_P2PMetrics_DiskStatus struct { func (x *StatusResponse_P2PMetrics_DiskStatus) Reset() { *x = StatusResponse_P2PMetrics_DiskStatus{} - mi := &file_supernode_supernode_proto_msgTypes[17] + mi := &file_supernode_supernode_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1198,7 +1097,7 @@ func (x *StatusResponse_P2PMetrics_DiskStatus) String() string { func (*StatusResponse_P2PMetrics_DiskStatus) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_DiskStatus) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[17] + mi := &file_supernode_supernode_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1248,7 +1147,7 @@ type StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint struct { func (x *StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint) Reset() { *x = StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint{} - mi := &file_supernode_supernode_proto_msgTypes[20] + mi := &file_supernode_supernode_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1260,7 +1159,7 @@ func (x *StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint) String() string func (*StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[20] + mi := &file_supernode_supernode_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1319,7 +1218,7 @@ type StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint struct { func (x *StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint) Reset() { *x = StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint{} - mi := &file_supernode_supernode_proto_msgTypes[21] + mi := &file_supernode_supernode_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1331,7 +1230,7 @@ func (x *StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint) String() strin func (*StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint) ProtoMessage() {} func (x *StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint) ProtoReflect() protoreflect.Message { - mi := &file_supernode_supernode_proto_msgTypes[21] + mi := &file_supernode_supernode_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1411,7 +1310,7 @@ var file_supernode_supernode_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 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, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0xd9, 0x1b, 0x0a, 0x0e, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x84, 0x19, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x74, 0x69, @@ -1440,218 +1339,196 @@ var file_supernode_supernode_proto_rawDesc = []byte{ 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x0a, 0x70, 0x32, 0x70, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x3b, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x63, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x63, - 0x6f, 0x64, 0x65, 0x63, 0x1a, 0x82, 0x05, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x12, 0x39, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x42, 0x0a, - 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x82, 0x05, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, + 0x12, 0x42, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, + 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x73, 0x75, 0x70, - 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x68, 0x61, 0x72, 0x64, 0x77, - 0x61, 0x72, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x1a, 0x40, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, - 0x6f, 0x72, 0x65, 0x73, 0x1a, 0x84, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, - 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x67, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x07, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x62, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, - 0x65, 0x64, 0x5f, 0x67, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, - 0x64, 0x47, 0x62, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x67, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x61, 0x76, 0x61, 0x69, 0x6c, - 0x61, 0x62, 0x6c, 0x65, 0x47, 0x62, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, - 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x01, 0x0a, 0x07, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, - 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, - 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, - 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, - 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x6b, 0x0a, 0x0c, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, - 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, - 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x73, - 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x51, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x73, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x1a, 0xf3, 0x0e, 0x0a, 0x0a, 0x50, 0x32, - 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x50, 0x0a, 0x0b, 0x64, 0x68, 0x74, 0x5f, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, + 0x65, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x68, 0x61, + 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x53, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x1a, 0x40, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x23, 0x0a, 0x0d, + 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x1a, 0x84, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x67, 0x62, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x62, 0x12, 0x17, 0x0a, + 0x07, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, + 0x75, 0x73, 0x65, 0x64, 0x47, 0x62, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x61, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x47, 0x62, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x0c, 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0xab, + 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, + 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, + 0x0a, 0x0f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, + 0x75, 0x73, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x1a, 0x6b, 0x0a, 0x0c, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, + 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x51, 0x0a, 0x07, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x73, 0x5f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x73, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x70, + 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x1a, 0xf3, 0x0e, 0x0a, + 0x0a, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x50, 0x0a, 0x0b, 0x64, + 0x68, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x68, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x52, 0x0a, 0x64, 0x68, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x74, 0x0a, + 0x16, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x2e, 0x44, 0x68, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x0a, - 0x64, 0x68, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x74, 0x0a, 0x16, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x73, 0x75, 0x70, - 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x12, 0x65, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a, 0x08, 0x62, 0x61, 0x6e, 0x5f, 0x6c, - 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x75, 0x70, 0x65, - 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, - 0x42, 0x61, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x62, 0x61, 0x6e, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x4e, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, - 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x12, 0x43, 0x0a, 0x04, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x04, 0x64, 0x69, 0x73, 0x6b, 0x1a, 0xc0, 0x05, 0x0a, 0x0a, 0x44, 0x68, 0x74, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x73, 0x0a, 0x14, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, - 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x68, 0x74, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x12, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x76, 0x0a, 0x15, 0x62, 0x61, - 0x74, 0x63, 0x68, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x5f, 0x72, 0x65, 0x63, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x73, 0x75, 0x70, 0x65, - 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, - 0x44, 0x68, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x13, 0x62, - 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, 0x65, 0x63, 0x65, - 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x62, - 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x12, 0x68, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, - 0x53, 0x6b, 0x69, 0x70, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, - 0x68, 0x5f, 0x62, 0x61, 0x6e, 0x5f, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x68, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x42, - 0x61, 0x6e, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x8f, 0x01, 0x0a, - 0x11, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x12, - 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x0b, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x61, 0x74, 0x65, 0x1a, 0xc8, - 0x01, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, + 0x69, 0x63, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x12, 0x65, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, + 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, + 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x50, + 0x6f, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a, 0x08, 0x62, 0x61, + 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x42, 0x61, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x62, 0x61, 0x6e, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x04, 0x64, 0x69, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, + 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x04, 0x64, 0x69, 0x73, 0x6b, 0x1a, 0xc0, 0x05, 0x0a, 0x0a, 0x44, 0x68, + 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x73, 0x0a, 0x14, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x68, 0x74, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x12, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x76, 0x0a, + 0x15, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x5f, + 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x44, 0x68, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x13, 0x62, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, + 0x65, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, + 0x68, 0x5f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x68, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x42, 0x61, 0x6e, + 0x6e, 0x65, 0x64, 0x53, 0x6b, 0x69, 0x70, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x68, 0x6f, 0x74, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x5f, 0x62, 0x61, 0x6e, 0x5f, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x68, 0x6f, 0x74, 0x50, 0x61, + 0x74, 0x68, 0x42, 0x61, 0x6e, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, + 0x8f, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, - 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x4c, 0x6f, - 0x63, 0x61, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x66, 0x6f, 0x75, 0x6e, - 0x64, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x1a, 0x74, 0x0a, 0x0e, 0x48, 0x61, 0x6e, - 0x64, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x66, - 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x66, 0x61, - 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x1a, - 0x9d, 0x01, 0x0a, 0x08, 0x42, 0x61, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6e, 0x69, 0x78, 0x12, 0x1f, - 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x67, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x1a, - 0x65, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, - 0x12, 0x23, 0x0a, 0x0e, 0x70, 0x32, 0x70, 0x5f, 0x64, 0x62, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, - 0x6d, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x70, 0x32, 0x70, 0x44, 0x62, 0x53, - 0x69, 0x7a, 0x65, 0x4d, 0x62, 0x12, 0x2f, 0x0a, 0x14, 0x70, 0x32, 0x70, 0x5f, 0x64, 0x62, 0x5f, - 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x32, 0x70, 0x44, 0x62, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x55, 0x0a, 0x0a, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, 0x62, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x61, 0x6c, 0x6c, 0x4d, 0x62, 0x12, 0x17, 0x0a, 0x07, 0x75, - 0x73, 0x65, 0x64, 0x5f, 0x6d, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x75, 0x73, - 0x65, 0x64, 0x4d, 0x62, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x6d, 0x62, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x66, 0x72, 0x65, 0x65, 0x4d, 0x62, 0x1a, 0x7c, 0x0a, - 0x19, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 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, 0x49, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x42, 0x0a, 0x14, 0x43, - 0x6f, 0x6e, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 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, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, - 0x95, 0x02, 0x0a, 0x0b, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x53, 0x69, 0x7a, 0x65, - 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x64, 0x75, 0x6e, 0x64, 0x61, 0x6e, 0x63, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x72, 0x65, 0x64, 0x75, 0x6e, 0x64, 0x61, 0x6e, 0x63, 0x79, - 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x6d, - 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x4d, 0x62, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x64, 0x72, 0x6f, - 0x6f, 0x6d, 0x5f, 0x70, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x65, - 0x61, 0x64, 0x72, 0x6f, 0x6f, 0x6d, 0x50, 0x63, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x65, 0x6d, - 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0a, 0x6d, 0x65, 0x6d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4d, 0x62, 0x12, 0x28, 0x0a, 0x10, 0x6d, - 0x65, 0x6d, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x09, 0x10, - 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x32, 0xd7, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x70, 0x65, - 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, - 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, - 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, - 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x4c, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, - 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x69, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1e, + 0x0a, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x12, 0x21, + 0x0a, 0x0c, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x61, 0x74, + 0x65, 0x1a, 0xc8, 0x01, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x74, 0x72, 0x69, + 0x65, 0x76, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x74, 0x69, 0x6d, + 0x65, 0x55, 0x6e, 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x66, 0x6f, 0x75, 0x6e, + 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x5f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x66, + 0x6f, 0x75, 0x6e, 0x64, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x1a, 0x74, 0x0a, 0x0e, + 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x1a, 0x9d, 0x01, 0x0a, 0x08, 0x42, 0x61, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, + 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6e, 0x69, + 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x67, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x1a, 0x65, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0e, 0x70, 0x32, 0x70, 0x5f, 0x64, 0x62, 0x5f, 0x73, 0x69, + 0x7a, 0x65, 0x5f, 0x6d, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x70, 0x32, 0x70, + 0x44, 0x62, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x62, 0x12, 0x2f, 0x0a, 0x14, 0x70, 0x32, 0x70, 0x5f, + 0x64, 0x62, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x32, 0x70, 0x44, 0x62, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x55, 0x0a, 0x0a, 0x44, 0x69, 0x73, + 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, + 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x61, 0x6c, 0x6c, 0x4d, 0x62, 0x12, 0x17, + 0x0a, 0x07, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6d, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x06, 0x75, 0x73, 0x65, 0x64, 0x4d, 0x62, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x72, 0x65, 0x65, 0x5f, + 0x6d, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x66, 0x72, 0x65, 0x65, 0x4d, 0x62, + 0x1a, 0x7c, 0x0a, 0x19, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 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, + 0x49, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x32, 0x50, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x42, + 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x6e, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 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, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x32, 0xd7, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x69, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x36, 0x5a, 0x34, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x75, 0x6d, 0x65, 0x72, + 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, + 0x6f, 0x64, 0x65, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x6e, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1666,7 +1543,7 @@ func file_supernode_supernode_proto_rawDescGZIP() []byte { return file_supernode_supernode_proto_rawDescData } -var file_supernode_supernode_proto_msgTypes = make([]protoimpl.MessageInfo, 22) +var file_supernode_supernode_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_supernode_supernode_proto_goTypes = []any{ (*StatusRequest)(nil), // 0: supernode.StatusRequest (*ListServicesRequest)(nil), // 1: supernode.ListServicesRequest @@ -1677,19 +1554,18 @@ var file_supernode_supernode_proto_goTypes = []any{ (*StatusResponse_ServiceTasks)(nil), // 6: supernode.StatusResponse.ServiceTasks (*StatusResponse_Network)(nil), // 7: supernode.StatusResponse.Network (*StatusResponse_P2PMetrics)(nil), // 8: supernode.StatusResponse.P2PMetrics - (*StatusResponse_CodecConfig)(nil), // 9: supernode.StatusResponse.CodecConfig - (*StatusResponse_Resources_CPU)(nil), // 10: supernode.StatusResponse.Resources.CPU - (*StatusResponse_Resources_Memory)(nil), // 11: supernode.StatusResponse.Resources.Memory - (*StatusResponse_Resources_Storage)(nil), // 12: supernode.StatusResponse.Resources.Storage - (*StatusResponse_P2PMetrics_DhtMetrics)(nil), // 13: supernode.StatusResponse.P2PMetrics.DhtMetrics - (*StatusResponse_P2PMetrics_HandleCounters)(nil), // 14: supernode.StatusResponse.P2PMetrics.HandleCounters - (*StatusResponse_P2PMetrics_BanEntry)(nil), // 15: supernode.StatusResponse.P2PMetrics.BanEntry - (*StatusResponse_P2PMetrics_DatabaseStats)(nil), // 16: supernode.StatusResponse.P2PMetrics.DatabaseStats - (*StatusResponse_P2PMetrics_DiskStatus)(nil), // 17: supernode.StatusResponse.P2PMetrics.DiskStatus - nil, // 18: supernode.StatusResponse.P2PMetrics.NetworkHandleMetricsEntry - nil, // 19: supernode.StatusResponse.P2PMetrics.ConnPoolMetricsEntry - (*StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint)(nil), // 20: supernode.StatusResponse.P2PMetrics.DhtMetrics.StoreSuccessPoint - (*StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint)(nil), // 21: supernode.StatusResponse.P2PMetrics.DhtMetrics.BatchRetrievePoint + (*StatusResponse_Resources_CPU)(nil), // 9: supernode.StatusResponse.Resources.CPU + (*StatusResponse_Resources_Memory)(nil), // 10: supernode.StatusResponse.Resources.Memory + (*StatusResponse_Resources_Storage)(nil), // 11: supernode.StatusResponse.Resources.Storage + (*StatusResponse_P2PMetrics_DhtMetrics)(nil), // 12: supernode.StatusResponse.P2PMetrics.DhtMetrics + (*StatusResponse_P2PMetrics_HandleCounters)(nil), // 13: supernode.StatusResponse.P2PMetrics.HandleCounters + (*StatusResponse_P2PMetrics_BanEntry)(nil), // 14: supernode.StatusResponse.P2PMetrics.BanEntry + (*StatusResponse_P2PMetrics_DatabaseStats)(nil), // 15: supernode.StatusResponse.P2PMetrics.DatabaseStats + (*StatusResponse_P2PMetrics_DiskStatus)(nil), // 16: supernode.StatusResponse.P2PMetrics.DiskStatus + nil, // 17: supernode.StatusResponse.P2PMetrics.NetworkHandleMetricsEntry + nil, // 18: supernode.StatusResponse.P2PMetrics.ConnPoolMetricsEntry + (*StatusResponse_P2PMetrics_DhtMetrics_StoreSuccessPoint)(nil), // 19: supernode.StatusResponse.P2PMetrics.DhtMetrics.StoreSuccessPoint + (*StatusResponse_P2PMetrics_DhtMetrics_BatchRetrievePoint)(nil), // 20: supernode.StatusResponse.P2PMetrics.DhtMetrics.BatchRetrievePoint } var file_supernode_supernode_proto_depIdxs = []int32{ 3, // 0: supernode.ListServicesResponse.services:type_name -> supernode.ServiceInfo @@ -1697,28 +1573,27 @@ var file_supernode_supernode_proto_depIdxs = []int32{ 6, // 2: supernode.StatusResponse.running_tasks:type_name -> supernode.StatusResponse.ServiceTasks 7, // 3: supernode.StatusResponse.network:type_name -> supernode.StatusResponse.Network 8, // 4: supernode.StatusResponse.p2p_metrics:type_name -> supernode.StatusResponse.P2PMetrics - 9, // 5: supernode.StatusResponse.codec:type_name -> supernode.StatusResponse.CodecConfig - 10, // 6: supernode.StatusResponse.Resources.cpu:type_name -> supernode.StatusResponse.Resources.CPU - 11, // 7: supernode.StatusResponse.Resources.memory:type_name -> supernode.StatusResponse.Resources.Memory - 12, // 8: supernode.StatusResponse.Resources.storage_volumes:type_name -> supernode.StatusResponse.Resources.Storage - 13, // 9: supernode.StatusResponse.P2PMetrics.dht_metrics:type_name -> supernode.StatusResponse.P2PMetrics.DhtMetrics - 18, // 10: supernode.StatusResponse.P2PMetrics.network_handle_metrics:type_name -> supernode.StatusResponse.P2PMetrics.NetworkHandleMetricsEntry - 19, // 11: supernode.StatusResponse.P2PMetrics.conn_pool_metrics:type_name -> supernode.StatusResponse.P2PMetrics.ConnPoolMetricsEntry - 15, // 12: supernode.StatusResponse.P2PMetrics.ban_list:type_name -> supernode.StatusResponse.P2PMetrics.BanEntry - 16, // 13: supernode.StatusResponse.P2PMetrics.database:type_name -> supernode.StatusResponse.P2PMetrics.DatabaseStats - 17, // 14: supernode.StatusResponse.P2PMetrics.disk:type_name -> supernode.StatusResponse.P2PMetrics.DiskStatus - 20, // 15: supernode.StatusResponse.P2PMetrics.DhtMetrics.store_success_recent:type_name -> supernode.StatusResponse.P2PMetrics.DhtMetrics.StoreSuccessPoint - 21, // 16: supernode.StatusResponse.P2PMetrics.DhtMetrics.batch_retrieve_recent:type_name -> supernode.StatusResponse.P2PMetrics.DhtMetrics.BatchRetrievePoint - 14, // 17: supernode.StatusResponse.P2PMetrics.NetworkHandleMetricsEntry.value:type_name -> supernode.StatusResponse.P2PMetrics.HandleCounters - 0, // 18: supernode.SupernodeService.GetStatus:input_type -> supernode.StatusRequest - 1, // 19: supernode.SupernodeService.ListServices:input_type -> supernode.ListServicesRequest - 4, // 20: supernode.SupernodeService.GetStatus:output_type -> supernode.StatusResponse - 2, // 21: supernode.SupernodeService.ListServices:output_type -> supernode.ListServicesResponse - 20, // [20:22] is the sub-list for method output_type - 18, // [18:20] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 9, // 5: supernode.StatusResponse.Resources.cpu:type_name -> supernode.StatusResponse.Resources.CPU + 10, // 6: supernode.StatusResponse.Resources.memory:type_name -> supernode.StatusResponse.Resources.Memory + 11, // 7: supernode.StatusResponse.Resources.storage_volumes:type_name -> supernode.StatusResponse.Resources.Storage + 12, // 8: supernode.StatusResponse.P2PMetrics.dht_metrics:type_name -> supernode.StatusResponse.P2PMetrics.DhtMetrics + 17, // 9: supernode.StatusResponse.P2PMetrics.network_handle_metrics:type_name -> supernode.StatusResponse.P2PMetrics.NetworkHandleMetricsEntry + 18, // 10: supernode.StatusResponse.P2PMetrics.conn_pool_metrics:type_name -> supernode.StatusResponse.P2PMetrics.ConnPoolMetricsEntry + 14, // 11: supernode.StatusResponse.P2PMetrics.ban_list:type_name -> supernode.StatusResponse.P2PMetrics.BanEntry + 15, // 12: supernode.StatusResponse.P2PMetrics.database:type_name -> supernode.StatusResponse.P2PMetrics.DatabaseStats + 16, // 13: supernode.StatusResponse.P2PMetrics.disk:type_name -> supernode.StatusResponse.P2PMetrics.DiskStatus + 19, // 14: supernode.StatusResponse.P2PMetrics.DhtMetrics.store_success_recent:type_name -> supernode.StatusResponse.P2PMetrics.DhtMetrics.StoreSuccessPoint + 20, // 15: supernode.StatusResponse.P2PMetrics.DhtMetrics.batch_retrieve_recent:type_name -> supernode.StatusResponse.P2PMetrics.DhtMetrics.BatchRetrievePoint + 13, // 16: supernode.StatusResponse.P2PMetrics.NetworkHandleMetricsEntry.value:type_name -> supernode.StatusResponse.P2PMetrics.HandleCounters + 0, // 17: supernode.SupernodeService.GetStatus:input_type -> supernode.StatusRequest + 1, // 18: supernode.SupernodeService.ListServices:input_type -> supernode.ListServicesRequest + 4, // 19: supernode.SupernodeService.GetStatus:output_type -> supernode.StatusResponse + 2, // 20: supernode.SupernodeService.ListServices:output_type -> supernode.ListServicesResponse + 19, // [19:21] is the sub-list for method output_type + 17, // [17:19] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_supernode_supernode_proto_init() } @@ -1732,7 +1607,7 @@ func file_supernode_supernode_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_supernode_supernode_proto_rawDesc, NumEnums: 0, - NumMessages: 22, + NumMessages: 21, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/supernode/supernode.swagger.json b/gen/supernode/supernode.swagger.json index 51f22046..e29dcbae 100644 --- a/gen/supernode/supernode.swagger.json +++ b/gen/supernode/supernode.swagger.json @@ -315,46 +315,6 @@ } } }, - "StatusResponseCodecConfig": { - "type": "object", - "properties": { - "symbolSize": { - "type": "integer", - "format": "int64", - "title": "bytes (typically 65535)" - }, - "redundancy": { - "type": "integer", - "format": "int64", - "title": "repair factor (percent-like scalar; 5 = default)" - }, - "maxMemoryMb": { - "type": "string", - "format": "uint64", - "title": "memory cap for native decoder" - }, - "concurrency": { - "type": "integer", - "format": "int64", - "title": "native decoder parallelism" - }, - "headroomPct": { - "type": "integer", - "format": "int32", - "title": "reserved memory percentage (0-90)" - }, - "memLimitMb": { - "type": "string", - "format": "uint64", - "title": "detected memory limit (MB)" - }, - "memLimitSource": { - "type": "string", - "title": "detection source (cgroup/meminfo)" - } - }, - "title": "RaptorQ codec configuration (effective values)" - }, "StatusResponseNetwork": { "type": "object", "properties": { @@ -553,9 +513,6 @@ }, "p2pMetrics": { "$ref": "#/definitions/StatusResponseP2PMetrics" - }, - "codec": { - "$ref": "#/definitions/StatusResponseCodecConfig" } }, "title": "The StatusResponse represents system status with clear organization" diff --git a/pkg/codec/README.md b/pkg/codec/README.md deleted file mode 100644 index 8e38b23f..00000000 --- a/pkg/codec/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Codec (RaptorQ) Guide - -## Overview -- Thin, well‑scoped API around RaptorQ for encoding/decoding cascade artefacts. -- Fixed policy (no env vars, no profiles), tuned for predictable behavior. - -## What It Does -- Per‑request processor: create/free a processor per Encode/Decode to bound native memory. -- Decode hygiene: write symbols to disk and drop in‑memory buffers before decoding to lower peaks. -- Layout file: stored as `_raptorq_layout.json` in the request’s symbols directory. -- Directory layout: - - Encode → `//` - - Decode → `//` (decoded output sits alongside) - -## Fixed Policy -- Concurrency: `4` -- Symbol size: `65535` -- Redundancy: `5` -- Max memory: system/cgroup memory minus `10%` headroom (no environment overrides) - -## Where It Applies -- Encode: `pkg/codec/raptorq.go::Encode()` → compute block size, `EncodeFile()`, read layout -- Decode: `pkg/codec/decode.go::Decode()` → write symbols + layout to disk, `DecodeSymbols()` - -## Notes -- Error code vs message: treat the error code as authoritative; message is context only -- Disk usage: ensure `` has space for symbols and the final file -- Cleanup: callers delete the decode temp dir (`DecodeTmpDir`) - -## Minimal Usage (Decode) -```go -resp, err := codecImpl.Decode(ctx, codec.DecodeRequest{ - ActionID: actionID, - Layout: layout, - Symbols: symbols, // map[id]payload -}) -// resp.Path is the reconstructed file; resp.DecodeTmpDir holds symbols + layout -``` - -## Minimal Usage (Encode) -```go -resp, err := codecImpl.Encode(ctx, codec.EncodeRequest{ - TaskID: taskID, - Path: inputPath, - DataSize: sizeBytes, -}) -// resp.SymbolsDir contains symbols; resp.Metadata holds the layout to publish -``` - -## Troubleshooting -- “memory limit exceeded” with integrity text: treat the error code as authoritative; the message may include integrity hints. -- Decode failures: progressive helper escalates symbol count automatically; non‑integrity errors bubble up immediately. diff --git a/pkg/codec/codec.go b/pkg/codec/codec.go index 329a0ba5..39029569 100644 --- a/pkg/codec/codec.go +++ b/pkg/codec/codec.go @@ -1,16 +1,5 @@ //go:generate mockgen -destination=codec_mock.go -package=codec -source=codec.go -// Package codec provides an abstraction over the RaptorQ encoding/decoding engine -// used by the supernode for cascade artefacts. It centralizes safe encode/decode -// workflows with a fixed policy (no environment overrides): -// - Concurrency: 4 -// - Symbol size: 65535 -// - Redundancy: 5 -// - Max memory: detected system/cgroup memory minus slight headroom (10%) -// -// Decode Memory Hygiene: Symbols passed in memory are written to disk immediately -// and dropped from RAM during decode to minimize overlapping heap and native -// allocations. package codec import ( diff --git a/pkg/codec/codec_default_test.go b/pkg/codec/codec_default_test.go new file mode 100644 index 00000000..537a8d7d --- /dev/null +++ b/pkg/codec/codec_default_test.go @@ -0,0 +1,122 @@ +package codec + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "testing" +) + +// Constants: set InputPath and TaskID. BaseDir is the current directory. +const ( + BaseDir = "" + InputPath = "" // set to an existing file path before running + TaskID = "rq-dirA" // both tests use the same directory +) + +// TestEncode_ToDirA encodes InputPath into BaseDir/TaskID using default settings. +func TestEncode_ToDirA(t *testing.T) { + if InputPath == "" { + t.Skip("set InputPath constant to a file path to run this test") + } + + fi, err := os.Stat(InputPath) + if err != nil { + t.Fatalf("stat input: %v", err) + } + + c := NewRaptorQCodec(BaseDir) + resp, err := c.Encode(context.TODO(), EncodeRequest{TaskID: TaskID, Path: InputPath, DataSize: int(fi.Size())}) + if err != nil { + t.Fatalf("encode: %v", err) + } + t.Logf("encoded to: %s", resp.SymbolsDir) + + // Log theoretical minimum percentage of symbols needed per block + for _, b := range resp.Metadata.Blocks { + s := int64(rqSymbolSize) + if s <= 0 { + s = 65535 + } + k := int((b.Size + s - 1) / s) // source symbols count + ttotal := len(b.Symbols) // total symbols count + if ttotal > 0 { + pct := 100.0 * float64(k) / float64(ttotal) + t.Logf("block %d: min ~= %.2f%% (K=%d, Total=%d)", b.BlockID, pct, k, ttotal) + } else { + t.Logf("block %d: no symbols found to compute min%%", b.BlockID) + } + } +} + +// TestDecode_FromDirA decodes using symbols created by TestEncode_ToDirA from the same directory. +// No deep assertions; only success/failure of decode is checked. +func TestDecode_FromDirA(t *testing.T) { + symbolsDir := filepath.Join(BaseDir, TaskID) + + if InputPath == "" { + t.Skip("set InputPath constant to a file path to run this test") + } + // Load layout from disk (prefer library-produced name) + var layout Layout + var layoutPath string + for _, name := range []string{"_raptorq_layout.json", "layout.json"} { + p := filepath.Join(symbolsDir, name) + if _, err := os.Stat(p); err == nil { + layoutPath = p + break + } + } + if layoutPath == "" { + t.Fatalf("layout file not found in %s", symbolsDir) + } + data, err := os.ReadFile(layoutPath) + if err != nil { + t.Fatalf("read layout: %v", err) + } + if err := json.Unmarshal(data, &layout); err != nil { + t.Fatalf("unmarshal layout: %v", err) + } + + // Load symbols into memory per layout + syms := make(map[string][]byte) + for _, b := range layout.Blocks { + blockDir := filepath.Join(symbolsDir, "block_"+itoa(b.BlockID)) + for _, id := range b.Symbols { + p := filepath.Join(blockDir, id) + if sdata, err := os.ReadFile(p); err == nil { + syms[id] = sdata + } + } + } + + c := NewRaptorQCodec(BaseDir) + _, err = c.Decode(context.TODO(), DecodeRequest{ActionID: TaskID, Layout: layout, Symbols: syms}) + if err != nil { + t.Fatalf("decode: %v", err) + } + t.Logf("decode succeeded for dir: %s", symbolsDir) +} + +func itoa(i int) string { + if i == 0 { + return "0" + } + neg := i < 0 + if neg { + i = -i + } + var b [20]byte + n := len(b) + for i > 0 { + n-- + b[n] = byte('0' + i%10) + i /= 10 + } + if neg { + n-- + b[n] = '-' + } + return string(b[n:]) +} diff --git a/pkg/codec/decode.go b/pkg/codec/decode.go index d2b99091..beeed5a8 100644 --- a/pkg/codec/decode.go +++ b/pkg/codec/decode.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" + raptorq "github.com/LumeraProtocol/rq-go" "github.com/LumeraProtocol/supernode/v2/pkg/logtrace" ) @@ -29,8 +30,8 @@ func (rq *raptorQ) Decode(ctx context.Context, req DecodeRequest) (DecodeRespons } logtrace.Info(ctx, "RaptorQ decode request received", fields) - // Create processor using fixed policy (no env overrides) - processor, err := newProcessor(ctx) + // Use deterministic processor settings (matching encoder) + processor, err := raptorq.NewRaptorQProcessor(rqSymbolSize, rqRedundancyFactor, rqMaxMemoryMB, rqConcurrency) if err != nil { fields[logtrace.FieldError] = err.Error() return DecodeResponse{}, fmt.Errorf("create RaptorQ processor: %w", err) @@ -43,42 +44,49 @@ func (rq *raptorQ) Decode(ctx context.Context, req DecodeRequest) (DecodeRespons return DecodeResponse{}, fmt.Errorf("mkdir %s: %w", symbolsDir, err) } - // Build a reverse index from symbol ID -> block ID from the provided layout - symToBlock := buildSymbolToBlockIndex(req.Layout) + // Build symbol->block mapping from layout and ensure block directories exist + symbolToBlock := make(map[string]int) + for _, blk := range req.Layout.Blocks { + blockDir := filepath.Join(symbolsDir, fmt.Sprintf("block_%d", blk.BlockID)) + if err := os.MkdirAll(blockDir, 0o755); err != nil { + fields[logtrace.FieldError] = err.Error() + return DecodeResponse{}, fmt.Errorf("mkdir %s: %w", blockDir, err) + } + for _, sym := range blk.Symbols { + symbolToBlock[sym] = blk.BlockID + } + } - // Write symbols to disk promptly to reduce heap residency. Place them under - // symbolsDir/block_/ to match rq-go expectations. - if err := writeSymbolsPerBlock(ctx, symbolsDir, symToBlock, req.Symbols); err != nil { - fields[logtrace.FieldError] = err.Error() - return DecodeResponse{}, err + // Write symbols to their respective block directories + for id, data := range req.Symbols { + blkID, ok := symbolToBlock[id] + if !ok { + fields[logtrace.FieldError] = "symbol not present in layout" + return DecodeResponse{}, fmt.Errorf("symbol %s not present in layout", id) + } + blockDir := filepath.Join(symbolsDir, fmt.Sprintf("block_%d", blkID)) + symbolPath := filepath.Join(blockDir, id) + if err := os.WriteFile(symbolPath, data, 0o644); err != nil { + fields[logtrace.FieldError] = err.Error() + return DecodeResponse{}, fmt.Errorf("write symbol %s: %w", id, err) + } } - logtrace.Info(ctx, "symbols written to disk (per-block)", fields) + logtrace.Info(ctx, "symbols written to block directories", fields) - // ---------- write layout file ---------- - // Use a conventional filename to match rq-go documentation examples. - // The library consumes the explicit path, so name is not strictly required, but - // aligning with `_raptorq_layout.json` aids operators/debuggers. - layoutPath, err := writeLayoutFile(req.Layout, symbolsDir) + // ---------- write layout.json ---------- + layoutPath := filepath.Join(symbolsDir, "layout.json") + layoutBytes, err := json.Marshal(req.Layout) if err != nil { fields[logtrace.FieldError] = err.Error() - return DecodeResponse{}, err + return DecodeResponse{}, fmt.Errorf("marshal layout: %w", err) } - logtrace.Info(ctx, "layout.json written", fields) - - // ---------- preflight check: ensure at least one symbol exists for each block ---------- - perBlockCounts := computePerBlockCounts(req.Layout, symbolsDir) - fields["per_block_counts"] = perBlockCounts - logtrace.Info(ctx, "pre-decode per-block symbol counts", fields) - - // If any block has zero symbols, fail fast with an "insufficient symbols" message - // so the progressive retriever can escalate and fetch more. - for _, blk := range req.Layout.Blocks { - if perBlockCounts[blk.BlockID] == 0 { - return DecodeResponse{}, fmt.Errorf("insufficient symbols: no symbols found for block %d", blk.BlockID) - } + if err := os.WriteFile(layoutPath, layoutBytes, 0o644); err != nil { + fields[logtrace.FieldError] = err.Error() + return DecodeResponse{}, fmt.Errorf("write layout file: %w", err) } + logtrace.Info(ctx, "layout.json written", fields) - // Decode the symbols into an output file using the provided layout. + // Decode outputPath := filepath.Join(symbolsDir, "output") if err := processor.DecodeSymbols(symbolsDir, outputPath, layoutPath); err != nil { fields[logtrace.FieldError] = err.Error() @@ -89,75 +97,3 @@ func (rq *raptorQ) Decode(ctx context.Context, req DecodeRequest) (DecodeRespons logtrace.Info(ctx, "RaptorQ decoding completed successfully", fields) return DecodeResponse{Path: outputPath, DecodeTmpDir: symbolsDir}, nil } - -// buildSymbolToBlockIndex constructs a lookup from symbol ID to its block ID -// based on the provided layout. -func buildSymbolToBlockIndex(layout Layout) map[string]int { - m := make(map[string]int) - for _, blk := range layout.Blocks { - for _, sid := range blk.Symbols { - m[sid] = blk.BlockID - } - } - return m -} - -// writeSymbolsPerBlock writes symbols to per-block directories to match rq-go expectations. -// It also deletes each symbol from the provided map after persisting to reduce heap residency. -func writeSymbolsPerBlock(ctx context.Context, symbolsDir string, symToBlock map[string]int, symbols map[string][]byte) error { - for id, data := range symbols { - blockID, ok := symToBlock[id] - var destDir string - if ok { - destDir = filepath.Join(symbolsDir, fmt.Sprintf("block_%d", blockID)) - } else { - // Fallback: if symbol not present in layout (unexpected), keep at root. - destDir = symbolsDir - logtrace.Info(ctx, "symbol ID not present in layout; writing at root", logtrace.Fields{"symbol_id": id}) - } - if err := os.MkdirAll(destDir, 0o755); err != nil { - return fmt.Errorf("mkdir %s: %w", destDir, err) - } - symbolPath := filepath.Join(destDir, id) - if err := os.WriteFile(symbolPath, data, 0o644); err != nil { - return fmt.Errorf("write symbol %s: %w", id, err) - } - delete(symbols, id) - } - return nil -} - -// writeLayoutFile marshals and writes the layout JSON into the symbols directory. -func writeLayoutFile(layout Layout, symbolsDir string) (string, error) { - layoutPath := filepath.Join(symbolsDir, "_raptorq_layout.json") - layoutBytes, err := json.Marshal(layout) - if err != nil { - return "", fmt.Errorf("marshal layout: %w", err) - } - if err := os.WriteFile(layoutPath, layoutBytes, 0o644); err != nil { - return "", fmt.Errorf("write layout file: %w", err) - } - return layoutPath, nil -} - -// computePerBlockCounts counts non-directory, non-layout files under each block directory. -func computePerBlockCounts(layout Layout, symbolsDir string) map[int]int { - counts := make(map[int]int) - for _, blk := range layout.Blocks { - blockDir := filepath.Join(symbolsDir, fmt.Sprintf("block_%d", blk.BlockID)) - entries, err := os.ReadDir(blockDir) - if err != nil { - counts[blk.BlockID] = 0 - continue - } - c := 0 - for _, e := range entries { - if e.IsDir() || e.Name() == "_raptorq_layout.json" { - continue - } - c++ - } - counts[blk.BlockID] = c - } - return counts -} diff --git a/pkg/codec/raptorq.go b/pkg/codec/raptorq.go index f2437d15..86efbd79 100644 --- a/pkg/codec/raptorq.go +++ b/pkg/codec/raptorq.go @@ -6,23 +6,20 @@ import ( "fmt" "os" "path/filepath" - "strconv" - "strings" raptorq "github.com/LumeraProtocol/rq-go" "github.com/LumeraProtocol/supernode/v2/pkg/logtrace" ) -// Fixed policy (linux/amd64 only): -// - Concurrency: 1 -// - Symbol size: 65535 -// - Redundancy: 5 -// - Max memory: use detected system/cgroup memory with headroom const ( - fixedConcurrency = 1 - defaultRedundancy = 5 - headroomPct = 20 // simple fixed safety margin - targetBlockMB = 128 // cap block size on encode (MB); 0 means use recommended + rqSymbolSize uint16 = 65535 + rqRedundancyFactor uint8 = 6 + // Limit RaptorQ processor memory usage to ~2 GiB + rqMaxMemoryMB uint64 = 16 * 1024 // MB + // Concurrency tuned for 2 GiB limit and typical 8+ core CPUs + rqConcurrency uint64 = 6 + // Target single-block output for up to 1 GiB files with padding headroom (~1.25 GiB) + rqBlockSize int = 1280 * 1024 * 1024 // bytes (1,280 MiB) ) type raptorQ struct { @@ -36,86 +33,6 @@ func NewRaptorQCodec(dir string) Codec { } -// newProcessor constructs a RaptorQ processor using a fixed policy: -// - concurrency=1 -// - symbol size=65535 -// - redundancy=5 -// - max memory = detected system/cgroup memory with slight headroom -func newProcessor(ctx context.Context) (*raptorq.RaptorQProcessor, error) { - memLimitMB, memSource := detectMemoryLimitMB() - usableMemMB := computeUsableMem(memLimitMB, headroomPct) - - // Fixed params - symbolSize := uint16(raptorq.DefaultSymbolSize) - redundancy := uint8(defaultRedundancy) - concurrency := uint64(fixedConcurrency) - maxMemMB := usableMemMB - - perWorkerMB := uint64(0) - if concurrency > 0 { - perWorkerMB = maxMemMB / concurrency - } - logtrace.Info(ctx, "RaptorQ processor config", logtrace.Fields{ - "symbol_size": symbolSize, - "redundancy_factor": redundancy, - "max_memory_mb": maxMemMB, - "concurrency": concurrency, - "per_worker_mb": perWorkerMB, - "headroom_pct": headroomPct, - "mem_limit_mb": memLimitMB, - "mem_limit_source": memSource, - }) - - return raptorq.NewRaptorQProcessor(symbolSize, redundancy, maxMemMB, concurrency) -} - -// detectMemoryLimitMB determines the memory limit (MB) from cgroups, falling back to MemTotal. -func detectMemoryLimitMB() (uint64, string) { - // cgroup v2: /sys/fs/cgroup/memory.max - if b, err := os.ReadFile("/sys/fs/cgroup/memory.max"); err == nil { - s := strings.TrimSpace(string(b)) - if s != "max" { - if v, err := strconv.ParseUint(s, 10, 64); err == nil && v > 0 { - return v / (1024 * 1024), "cgroupv2:memory.max" - } - } - } - // cgroup v1: /sys/fs/cgroup/memory/memory.limit_in_bytes - if b, err := os.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes"); err == nil { - s := strings.TrimSpace(string(b)) - if v, err := strconv.ParseUint(s, 10, 64); err == nil && v > 0 { - // Some systems report a huge number when unlimited; treat > 1PB as unlimited - if v <= 1<<50 { - return v / (1024 * 1024), "cgroupv1:memory.limit_in_bytes" - } - // unlimited; fallthrough to MemTotal - } - } - // Fallback: /proc/meminfo MemTotal - if b, err := os.ReadFile("/proc/meminfo"); err == nil { - lines := strings.Split(string(b), "\n") - for _, ln := range lines { - if strings.HasPrefix(ln, "MemTotal:") { - f := strings.Fields(ln) - if len(f) >= 2 { - if kb, err := strconv.ParseUint(f[1], 10, 64); err == nil { - return kb / 1024, "meminfo:MemTotal" - } - } - } - } - } - return 0, "unknown" -} - -// computeUsableMem applies a headroom percentage to a memory limit using integer math. -func computeUsableMem(memLimitMB uint64, headroomPct int) uint64 { - if headroomPct <= 0 || memLimitMB == 0 { - return memLimitMB - } - return memLimitMB - (memLimitMB*uint64(headroomPct))/100 -} - func (rq *raptorQ) Encode(ctx context.Context, req EncodeRequest) (EncodeResponse, error) { /* ---------- 1. initialise RaptorQ processor ---------- */ fields := logtrace.Fields{ @@ -126,8 +43,7 @@ func (rq *raptorQ) Encode(ctx context.Context, req EncodeRequest) (EncodeRespons "data-size": req.DataSize, } - // Create processor using fixed policy (linux/amd64, no env) - processor, err := newProcessor(ctx) + processor, err := raptorq.NewRaptorQProcessor(rqSymbolSize, rqRedundancyFactor, rqMaxMemoryMB, rqConcurrency) if err != nil { return EncodeResponse{}, fmt.Errorf("create RaptorQ processor: %w", err) } @@ -135,20 +51,8 @@ func (rq *raptorQ) Encode(ctx context.Context, req EncodeRequest) (EncodeRespons logtrace.Info(ctx, "RaptorQ processor created", fields) /* ---------- 1. run the encoder ---------- */ - // Determine block size with a simple cap (no env): use min(recommended, targetBlockMB) - rec := processor.GetRecommendedBlockSize(uint64(req.DataSize)) - var blockSize int - if targetBlockMB > 0 { - targetBytes := int(targetBlockMB) * 1024 * 1024 - if rec == 0 || rec > targetBytes { - blockSize = targetBytes - } else { - blockSize = rec - } - } else { - blockSize = rec - } - logtrace.Info(ctx, "RaptorQ recommended block size", logtrace.Fields{"block_size": rec, "chosen_block_size": blockSize, "target_block_mb": targetBlockMB}) + // Deterministic: force single block + blockSize := rqBlockSize symbolsDir := filepath.Join(rq.symbolsBaseDir, req.TaskID) if err := os.MkdirAll(symbolsDir, 0o755); err != nil { @@ -165,7 +69,8 @@ func (rq *raptorQ) Encode(ctx context.Context, req EncodeRequest) (EncodeRespons return EncodeResponse{}, fmt.Errorf("raptorq encode: %w", err) } - // layout will be read from disk below + /* we no longer need the temp file */ + // _ = os.Remove(tmpPath) /* ---------- 2. read the layout JSON ---------- */ layoutData, err := os.ReadFile(resp.LayoutFilePath) @@ -182,5 +87,10 @@ func (rq *raptorQ) Encode(ctx context.Context, req EncodeRequest) (EncodeRespons } encodeResp.SymbolsDir = symbolsDir + // Enforce single-block output; abort if multiple blocks are produced + if n := len(encodeResp.Metadata.Blocks); n != 1 { + return EncodeResponse{}, fmt.Errorf("raptorq encode produced %d blocks; single-block layout is required", n) + } + return encodeResp, nil } diff --git a/pkg/codecconfig/config.go b/pkg/codecconfig/config.go deleted file mode 100644 index 55bc41f0..00000000 --- a/pkg/codecconfig/config.go +++ /dev/null @@ -1,97 +0,0 @@ -package codecconfig - -import ( - "context" - "os" - "strconv" - "strings" -) - -// Config describes the effective codec configuration (fixed policy; no env). -type Config struct { - SymbolSize uint16 - Redundancy uint8 - MaxMemoryMB uint64 - Concurrency uint64 - HeadroomPct int - MemLimitMB uint64 - MemLimitSource string -} - -// Defaults mirrored from rq-go and current project conventions. -const ( - defaultSymbolSize = 65535 - defaultRedundancy = 5 - fixedConcurrency = 4 - headroomPct = 10 -) - -// Current computes the current effective codec configuration (fixed policy). -func Current(ctx context.Context) Config { - memLimitMB, memSource := detectMemoryLimitMB() - usableMemMB := computeUsableMem(memLimitMB, headroomPct) - - symbolSize := uint16(defaultSymbolSize) - redundancy := uint8(defaultRedundancy) - maxMemMB := usableMemMB - concurrency := uint64(fixedConcurrency) - - return Config{ - SymbolSize: symbolSize, - Redundancy: redundancy, - MaxMemoryMB: maxMemMB, - Concurrency: concurrency, - HeadroomPct: headroomPct, - MemLimitMB: memLimitMB, - MemLimitSource: memSource, - } -} - -func computeUsableMem(memLimitMB uint64, headroomPct int) uint64 { - if headroomPct <= 0 || memLimitMB == 0 { - return memLimitMB - } - return memLimitMB - (memLimitMB*uint64(headroomPct))/100 -} - -// detectMemoryLimitMB attempts to determine the memory limit (MB) from cgroups, falling back to MemTotal. -func detectMemoryLimitMB() (uint64, string) { - // cgroup v2: /sys/fs/cgroup/memory.max - if b, err := os.ReadFile("/sys/fs/cgroup/memory.max"); err == nil { - s := strings.TrimSpace(string(b)) - if s != "max" { - if v, err := strconv.ParseUint(s, 10, 64); err == nil && v > 0 { - return v / (1024 * 1024), "cgroupv2:memory.max" - } - } - } - // cgroup v1: /sys/fs/cgroup/memory/memory.limit_in_bytes - if b, err := os.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes"); err == nil { - s := strings.TrimSpace(string(b)) - if v, err := strconv.ParseUint(s, 10, 64); err == nil && v > 0 { - // Some systems report a huge number when unlimited; treat > 1PB as unlimited - if v > 1<<50 { - // unlimited; fallthrough to MemTotal - } else { - return v / (1024 * 1024), "cgroupv1:memory.limit_in_bytes" - } - } - } - // Fallback: /proc/meminfo MemTotal - if b, err := os.ReadFile("/proc/meminfo"); err == nil { - lines := strings.Split(string(b), "\n") - for _, ln := range lines { - if strings.HasPrefix(ln, "MemTotal:") { - f := strings.Fields(ln) - if len(f) >= 2 { - if kb, err := strconv.ParseUint(f[1], 10, 64); err == nil { - return kb / 1024, "meminfo:MemTotal" - } - } - } - } - } - return 0, "unknown" -} - -// No CPU quota detection needed for fixed policy. diff --git a/proto/supernode/supernode.proto b/proto/supernode/supernode.proto index b305756a..edbff3b0 100644 --- a/proto/supernode/supernode.proto +++ b/proto/supernode/supernode.proto @@ -157,21 +157,5 @@ message StatusResponse { } P2PMetrics p2p_metrics = 9; - - // RaptorQ codec configuration (effective values) - message CodecConfig { - uint32 symbol_size = 1; // bytes (typically 65535) - uint32 redundancy = 2; // repair factor (percent-like scalar; 5 = default) - uint64 max_memory_mb = 3; // memory cap for native decoder - uint32 concurrency = 4; // native decoder parallelism - // reserved field 5 (was: profile) - reserved 5; - int32 headroom_pct = 6; // reserved memory percentage (0-90) - uint64 mem_limit_mb = 7; // detected memory limit (MB) - string mem_limit_source = 8;// detection source (cgroup/meminfo) - // reserved fields 9 and 10 (were: effective_cores, cpu_limit_source) - reserved 9, 10; - } - - CodecConfig codec = 10; + } diff --git a/supernode/node/supernode/gateway/server.go b/supernode/node/supernode/gateway/server.go index db6852b5..5440a7f4 100644 --- a/supernode/node/supernode/gateway/server.go +++ b/supernode/node/supernode/gateway/server.go @@ -2,7 +2,6 @@ package gateway import ( "context" - "encoding/json" "fmt" "net" "net/http" @@ -12,7 +11,6 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" pb "github.com/LumeraProtocol/supernode/v2/gen/supernode" - "github.com/LumeraProtocol/supernode/v2/pkg/codecconfig" "github.com/LumeraProtocol/supernode/v2/pkg/logtrace" ) @@ -71,34 +69,6 @@ func (s *Server) Run(ctx context.Context) error { // Register Swagger endpoints httpMux.HandleFunc("/swagger.json", s.serveSwaggerJSON) httpMux.HandleFunc("/swagger-ui/", s.serveSwaggerUI) - // Expose minimal RaptorQ codec config (trimmed; no bloat) - httpMux.HandleFunc("/api/v1/codec", func(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) - return - } - cfg := codecconfig.Current(r.Context()) - type minimalCodec struct { - SymbolSize uint16 `json:"symbol_size"` - Redundancy uint8 `json:"redundancy"` - MaxMemoryMB uint64 `json:"max_memory_mb"` - Concurrency uint64 `json:"concurrency"` - HeadroomPct int `json:"headroom_pct"` - MemLimitMB uint64 `json:"mem_limit_mb"` - MemLimitSource string `json:"mem_limit_source"` - } - out := minimalCodec{ - SymbolSize: cfg.SymbolSize, - Redundancy: cfg.Redundancy, - MaxMemoryMB: cfg.MaxMemoryMB, - Concurrency: cfg.Concurrency, - HeadroomPct: cfg.HeadroomPct, - MemLimitMB: cfg.MemLimitMB, - MemLimitSource: cfg.MemLimitSource, - } - w.Header().Set("Content-Type", "application/json") - _ = json.NewEncoder(w).Encode(out) - }) httpMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { http.Redirect(w, r, "/swagger-ui/", http.StatusFound) diff --git a/supernode/node/supernode/server/status_server.go b/supernode/node/supernode/server/status_server.go index 0710cf4f..5a8cc156 100644 --- a/supernode/node/supernode/server/status_server.go +++ b/supernode/node/supernode/server/status_server.go @@ -6,7 +6,6 @@ import ( "google.golang.org/grpc" pb "github.com/LumeraProtocol/supernode/v2/gen/supernode" - "github.com/LumeraProtocol/supernode/v2/pkg/codecconfig" "github.com/LumeraProtocol/supernode/v2/supernode/services/common/supernode" ) @@ -178,17 +177,7 @@ func (s *SupernodeServer) GetStatus(ctx context.Context, req *pb.StatusRequest) response.P2PMetrics = pbpm } - // Populate codec configuration - cfg := codecconfig.Current(ctx) - response.Codec = &pb.StatusResponse_CodecConfig{ - SymbolSize: uint32(cfg.SymbolSize), - Redundancy: uint32(cfg.Redundancy), - MaxMemoryMb: cfg.MaxMemoryMB, - Concurrency: uint32(cfg.Concurrency), - HeadroomPct: int32(cfg.HeadroomPct), - MemLimitMb: cfg.MemLimitMB, - MemLimitSource: cfg.MemLimitSource, - } + // Codec configuration removed return response, nil } diff --git a/supernode/services/cascade/adaptors/p2p.go b/supernode/services/cascade/adaptors/p2p.go index fcaad76a..bc5697e3 100644 --- a/supernode/services/cascade/adaptors/p2p.go +++ b/supernode/services/cascade/adaptors/p2p.go @@ -21,7 +21,8 @@ import ( const ( loadSymbolsBatchSize = 2500 - storeSymbolsPercent = 10 + // Minimum first-pass coverage to store before returning from Register (percent) + storeSymbolsPercent = 18 ) // P2PService defines the interface for storing data in the P2P layer. @@ -149,9 +150,20 @@ func (p *p2pImpl) storeCascadeSymbols(ctx context.Context, taskID, actionID stri return 0, 0, 0, err } + totalAvailable := len(keys) + targetCount := int(math.Ceil(float64(totalAvailable) * storeSymbolsPercent / 100.0)) + if targetCount < 1 && totalAvailable > 0 { + targetCount = 1 + } + logtrace.Info(ctx, "first-pass target coverage (symbols)", logtrace.Fields{ + "total_symbols": totalAvailable, + "target_percent": storeSymbolsPercent, + "target_count": targetCount, + }) + /* down-sample if we exceed the “big directory” threshold ------------- */ if len(keys) > loadSymbolsBatchSize { - want := int(math.Ceil(float64(len(keys)) * storeSymbolsPercent / 100)) + want := targetCount if want < len(keys) { rand.Shuffle(len(keys), func(i, j int) { keys[i], keys[j] = keys[j], keys[i] }) keys = keys[:want] @@ -181,6 +193,16 @@ func (p *p2pImpl) storeCascadeSymbols(ctx context.Context, taskID, actionID stri start = end } + achievedPct := 0.0 + if totalAvailable > 0 { + achievedPct = (float64(totalSymbols) / float64(totalAvailable)) * 100.0 + } + logtrace.Info(ctx, "first-pass achieved coverage (symbols)", logtrace.Fields{ + "achieved_symbols": totalSymbols, + "achieved_percent": achievedPct, + "total_requests": totalRequests, + }) + if err := p.rqStore.UpdateIsFirstBatchStored(actionID); err != nil { return 0, totalSymbols, totalRequests, fmt.Errorf("update first-batch flag: %w", err) } diff --git a/supernode/services/cascade/progressive_decode.go b/supernode/services/cascade/progressive_decode.go index 0b46e06d..65cd6820 100644 --- a/supernode/services/cascade/progressive_decode.go +++ b/supernode/services/cascade/progressive_decode.go @@ -3,25 +3,16 @@ package cascade import ( "context" "fmt" - "math" - "strings" "github.com/LumeraProtocol/supernode/v2/pkg/codec" "github.com/LumeraProtocol/supernode/v2/pkg/logtrace" "github.com/LumeraProtocol/supernode/v2/supernode/services/cascade/adaptors" ) -// retrieveAndDecodeProgressively progressively retrieves symbols and attempts decode at -// increasing thresholds to avoid over-fetching and reduce memory pressure. -// -// The progressive retrieval + decode loop originally lived in -// download.go::restoreFileFromLayout. It is moved here to isolate the control-flow from -// the main task logic, making Download/restoreFileFromLayout easier to follow and test. -// -// Prior implementation fetched a fixed minimum percentage and failed -// immediately on decode errors. In cases with symbol set skew or peer inconsistency, this -// could lead to repeated failures or fetching too many symbols upfront, increasing memory -// pressure. This helper escalates in steps (9%, 25%, 50%, 75%, 100%). +// retrieveAndDecodeProgressively performs a minimal two-step retrieval for a single-block layout: +// 1) Fetch approximately requiredSymbolPercent of symbols and try decoding. +// 2) If that fails, fetch all available symbols from the block and try again. +// This replaces earlier multi-block balancing and multi-threshold escalation. func (task *CascadeRegistrationTask) retrieveAndDecodeProgressively( ctx context.Context, layout codec.Layout, @@ -34,43 +25,38 @@ func (task *CascadeRegistrationTask) retrieveAndDecodeProgressively( } fields[logtrace.FieldActionID] = actionID - // escalate retrieval targets - percents := []int{requiredSymbolPercent, 25, 50, 75, 100} - seen := map[int]struct{}{} - ordered := make([]int, 0, len(percents)) - for _, p := range percents { - if p < requiredSymbolPercent { - continue - } - if _, ok := seen[p]; !ok { - seen[p] = struct{}{} - ordered = append(ordered, p) - } + if len(layout.Blocks) == 0 { + return adaptors.DecodeResponse{}, fmt.Errorf("empty layout: no blocks") } - // Build per-block symbol lists for balanced selection and compute total - perBlock, totalSymbols := makePerBlock(layout) + // Single-block fast path + if len(layout.Blocks) == 1 { + blk := layout.Blocks[0] + total := len(blk.Symbols) + if total == 0 { + return adaptors.DecodeResponse{}, fmt.Errorf("empty layout: no symbols") + } - var lastErr error - for _, p := range ordered { - reqCount := (totalSymbols*p + 99) / 100 - fields["targetPercent"] = p + // Step 1: try with requiredSymbolPercent of symbols + reqCount := (total*requiredSymbolPercent + 99) / 100 + if reqCount < 1 { + reqCount = 1 + } + if reqCount > total { + reqCount = total + } + fields["targetPercent"] = requiredSymbolPercent fields["targetCount"] = reqCount - logtrace.Info(ctx, "retrieving symbols for target percent", fields) + logtrace.Info(ctx, "retrieving initial symbols (single block)", fields) - // Build a balanced candidate key set ensuring some coverage per block. - candidateKeys := selectBalancedKeys(perBlock, layout, reqCount, totalSymbols) - - symbols, err := task.P2PClient.BatchRetrieve(ctx, candidateKeys, reqCount, actionID) + keys := blk.Symbols[:reqCount] + symbols, err := task.P2PClient.BatchRetrieve(ctx, keys, reqCount, actionID) if err != nil { fields[logtrace.FieldError] = err.Error() logtrace.Error(ctx, "failed to retrieve symbols", fields) return adaptors.DecodeResponse{}, fmt.Errorf("failed to retrieve symbols: %w", err) } - fields["retrievedSymbols"] = len(symbols) - logtrace.Info(ctx, "symbols retrieved", fields) - // Attempt decode decodeInfo, err := task.RQ.Decode(ctx, adaptors.DecodeRequest{ ActionID: actionID, Symbols: symbols, @@ -80,119 +66,21 @@ func (task *CascadeRegistrationTask) retrieveAndDecodeProgressively( return decodeInfo, nil } - // Only escalate for probable insufficiency/integrity errors; otherwise, fail fast - errStr := err.Error() - if p >= 100 || !(strings.Contains(errStr, "decoding failed") || - strings.Contains(strings.ToLower(errStr), "hash mismatch") || - strings.Contains(strings.ToLower(errStr), "insufficient") || - strings.Contains(strings.ToLower(errStr), "symbol")) { - fields[logtrace.FieldError] = errStr - logtrace.Error(ctx, "failed to decode symbols", fields) - return adaptors.DecodeResponse{}, fmt.Errorf("decode symbols using RaptorQ: %w", err) + // Step 2: escalate to all symbols + logtrace.Info(ctx, "initial decode failed; retrieving all symbols (single block)", nil) + symbols, err = task.P2PClient.BatchRetrieve(ctx, blk.Symbols, total, actionID) + if err != nil { + fields[logtrace.FieldError] = err.Error() + logtrace.Error(ctx, "failed to retrieve all symbols", fields) + return adaptors.DecodeResponse{}, fmt.Errorf("failed to retrieve symbols: %w", err) } - - logtrace.Info(ctx, "decode failed; escalating symbol target", logtrace.Fields{ - "last_error": errStr, + return task.RQ.Decode(ctx, adaptors.DecodeRequest{ + ActionID: actionID, + Symbols: symbols, + Layout: layout, }) - lastErr = err - } - - if lastErr != nil { - fields[logtrace.FieldError] = lastErr.Error() - logtrace.Error(ctx, "failed to decode symbols after escalation", fields) - return adaptors.DecodeResponse{}, fmt.Errorf("decode symbols using RaptorQ: %w", lastErr) - } - return adaptors.DecodeResponse{}, fmt.Errorf("decode symbols using RaptorQ: unknown failure") -} - -// makePerBlock returns a copy of per-block symbol slices and the total symbol count. -func makePerBlock(layout codec.Layout) (map[int][]string, int) { - perBlock := make(map[int][]string) - total := 0 - for _, blk := range layout.Blocks { - syms := make([]string, len(blk.Symbols)) - copy(syms, blk.Symbols) - perBlock[blk.BlockID] = syms - total += len(syms) } - return perBlock, total -} -// selectBalancedKeys chooses up to reqCount keys ensuring at least 1 per block when possible, -// then distributing the remainder roughly proportional to block sizes, and finally filling -// any gap via round-robin. totalSymbols is the sum of all per-block lengths. -func selectBalancedKeys(perBlock map[int][]string, layout codec.Layout, reqCount int, totalSymbols int) []string { - candidateKeys := make([]string, 0, reqCount) - blocks := layout.Blocks - // seed: at least one per block if possible - for _, blk := range blocks { - if len(candidateKeys) >= reqCount { - break - } - syms := perBlock[blk.BlockID] - if len(syms) > 0 { - candidateKeys = append(candidateKeys, syms[0]) - } - } - remaining := reqCount - len(candidateKeys) - if remaining <= 0 { - return candidateKeys - } - // quotas per block - quotas := make(map[int]int) - sumQuotas := 0 - for _, blk := range blocks { - blkTotal := len(perBlock[blk.BlockID]) - if blkTotal == 0 || totalSymbols == 0 { - quotas[blk.BlockID] = 0 - continue - } - q := int(math.Ceil(float64(remaining) * float64(blkTotal) / float64(totalSymbols))) - if q < 0 { - q = 0 - } - quotas[blk.BlockID] = q - sumQuotas += q - } - // normalize overshoot - for sumQuotas > remaining { - for _, blk := range blocks { - if sumQuotas <= remaining { - break - } - if quotas[blk.BlockID] > 0 { - quotas[blk.BlockID]-- - sumQuotas-- - } - } - } - // select additional symbols according to quotas - for _, blk := range blocks { - want := quotas[blk.BlockID] - if want <= 0 { - continue - } - syms := perBlock[blk.BlockID] - start := 1 // 0th may have been used in seed - for i := start; i < len(syms) && want > 0 && len(candidateKeys) < reqCount; i++ { - candidateKeys = append(candidateKeys, syms[i]) - want-- - } - } - // if still short (rounding/small blocks), round-robin fill - if len(candidateKeys) < reqCount { - for _, blk := range blocks { - if len(candidateKeys) >= reqCount { - break - } - syms := perBlock[blk.BlockID] - for i := 0; i < len(syms) && len(candidateKeys) < reqCount; i++ { - candidateKeys = append(candidateKeys, syms[i]) - } - } - } - if len(candidateKeys) > reqCount { - candidateKeys = candidateKeys[:reqCount] - } - return candidateKeys + // Multi-block layouts are not supported by current policy + return adaptors.DecodeResponse{}, fmt.Errorf("unsupported layout: expected 1 block, found %d", len(layout.Blocks)) }