diff --git a/cmd/ingestor/client_rx_minimised_test.go b/cmd/ingestor/client_rx_minimised_test.go index 8c6ca6794..dcd120f82 100644 --- a/cmd/ingestor/client_rx_minimised_test.go +++ b/cmd/ingestor/client_rx_minimised_test.go @@ -2,6 +2,11 @@ package main import ( "fmt" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" "testing" "time" ) @@ -36,7 +41,7 @@ const ( fwRouteTransportDirect = 0x03 ) -// Payload types — firmware/src/Packet.h:20-33. +// Payload types — firmware/src/Packet.h:19-32. const ( fwPayloadAdvert = 0x04 fwPayloadGrpTxt = 0x05 @@ -46,8 +51,9 @@ const ( // fwPayloadTypeShift mirrors firmware PH_TYPE_SHIFT (src/Packet.h:9). const fwPayloadTypeShift = 2 -// fwHeader builds the 1-byte header per firmware/src/Packet.h:8-12 -// (getRouteType/getPayloadType/getPayloadVer). Payload version is v1 (0). +// fwHeader builds the 1-byte header per the mask/shift defines on +// firmware/src/Packet.h:8-12 (PH_ROUTE_MASK, PH_TYPE_SHIFT, PH_VER_SHIFT, read +// back by Packet::getRouteType/getPayloadType/getPayloadVer). Version is v1 (0). func fwHeader(routeType, payloadType int) string { return fmt.Sprintf("%02x", (payloadType< len(lines) { + t.Errorf("%s is out of range: %s has %d lines", cite, r.file, len(lines)) + continue + } + for _, check := range []struct { + what string + line string + pat string + }{ + {"first", lines[r.from-1], r.firstRe}, + {"last", lines[r.to-1], r.lastRe}, + } { + if !regexp.MustCompile(check.pat).MatchString(check.line) { + t.Errorf("%s: %s line does not match %s — got %q", cite, check.what, check.pat, check.line) + } + } + } +} diff --git a/docs/client-rx-coverage.md b/docs/client-rx-coverage.md index a7888eb37..f0e6b1a5d 100644 --- a/docs/client-rx-coverage.md +++ b/docs/client-rx-coverage.md @@ -147,17 +147,24 @@ and `src/Packet.h`): - `path` — exactly `hop_count * hash_size` bytes. `path_length` must describe the bytes that are actually present; a byte count larger than the remaining buffer is rejected (dropped, not partially read). -- `payload` — omit entirely for non-adverts. A partially kept payload is tolerated too (it is simply - reported as undecodable), but there is no reason to send one. +- `payload` — omit entirely for non-adverts. A partially kept payload is tolerated too: the coverage + row is the same one the fully minimised packet writes, keyed on `path[last]`. There is no reason to + send one, and a remnant can still leak. A group payload is channel hash (1 byte) + cipher MAC + (2 bytes) + ciphertext ([firmware `docs/payloads.md`](https://github.com/meshcore-dev/MeshCore/blob/main/docs/payloads.md), + "Group text message"), so only a remnant *shorter* than that 3-byte envelope is reported as + undecodable — keep 3 bytes or more and the channel hash and the MAC are published. **Adverts are the exception: send them whole.** For a 0-hop advert the heard key *is* the advertiser's pubkey, and that lives in the advert payload — a minimised 0-hop advert carries nothing -attributable and is dropped. A *relayed* advert follows the normal path rule, so it survives +attributable and is dropped. Truncating the payload to just the 32-byte pubkey does not help either: +an advert payload is pubkey (32) + timestamp (4) + signature (64), and all 100 bytes must be present +before the pubkey is read back. A *relayed* advert follows the normal path rule, so it survives minimisation, but there is no benefit in special-casing it client-side. What minimisation does **not** change: `DIRECT`/`TRANSPORT_DIRECT` paths and `TRACE` packets stay unattributable, and 1-byte path hashes stay excluded. Dropping the payload never widens what is -recorded. Pinned by `TestHandleClientPacketMinimised*` in `cmd/ingestor/client_rx_minimised_test.go`. +recorded. Pinned by `TestHandleClientPacketMinimised*` and +`TestHandleClientPacketPartialPayloadTolerated` in `cmd/ingestor/client_rx_minimised_test.go`. ## Capture HARD RULE — only what was heard directly