Document embedded batch signatures and resize pressure fixtures
This commit is contained in:
1 parent
98d1e40bf3
commit
01d7fd5bef
2 files changed
+50
-39
No files matched your search
+49
-38
@@ -9,11 +9,12 @@
|
||||
Принятые решения:
|
||||
- Транспорт — существующий ETCP с быстрыми переповторами, мультилинком, шифрованием и управлением нагрузкой.
|
||||
- Параметры FEC задаёт источник; 6+2 — значение по умолчанию, а не ограничение протокола.
|
||||
- Источник подписывает каждый блок после разбиения на субпотоки, включая проверочные блоки.
|
||||
- Источник подписывает всю пачку один раз до RS; подпись восстанавливается вместе с содержимым и проверяется после decode.
|
||||
- В источник добавляется циклический timestamp uint16_t в миллисекундах; он сохраняется при всей ретрансляции.
|
||||
Задержка оценивается относительно предыдущих данных по дельтам timestamp и времени прихода, включая полную остановку.
|
||||
- Передаём произвольные данные как есть, без обработки форматов видео, кадров и ключевых точек.
|
||||
- Размер одной кодограммы после разбиения — около 1300 байт; источник сбрасывает неполную пачку через 100 мс.
|
||||
- Размер части автоматически уменьшается по длине пачки, максимум по умолчанию 1300 байт.
|
||||
Побайтовый источник сбрасывает остаток через 100 мс; publish_block публикует сразу.
|
||||
- На каждый локальный экземпляр трансляции — кольцевой буфер 32 МБ для всех её субпотоков вместе.
|
||||
Вся выдача идёт из этого буфера. Вытесненные данные недоступны: не успел получить — опоздал.
|
||||
- Отдельных дозапросов диапазонов нет. Единственный способ получения — запросить субпоток с индекса или с конца.
|
||||
@@ -74,27 +75,36 @@ INFO/SUBSCRIBE/REVERSE_REQ к неподписанному узлу получа
|
||||
- Номера возрастают без повторов; UINT64_MAX зарезервирован для запроса с конца.
|
||||
Переполнение требует новой source_epoch.
|
||||
|
||||
Дескриптор содержит ключ трансляции, n, r и размер RS-кодограммы block_size.
|
||||
Дескриптор содержит ключ трансляции, n, r и максимальный размер RS-кодограммы block_size.
|
||||
Параметры задаёт только источник и не меняет в пределах source_epoch; изменение создаёт новый запуск.
|
||||
Дескриптор подтверждается подписанной опцией источника; поля FEC также входят в подписанный блок.
|
||||
Дескриптор подтверждается подписанной опцией источника; поля FEC также входят в подписанную пачку.
|
||||
Ограничения кодека: 1 <= n <= 255, 0 <= r < n, 10 <= block_size <= 4096.
|
||||
Кроме допустимости RS проверяется расход памяти и корректность полного размера блока.
|
||||
Кроме допустимости RS проверяются расход памяти и место для подписанных метаданных, подписи и хотя бы одного байта содержимого.
|
||||
|
||||
Целевой размер неизменяемого блока субпотока — около 1300 байт, включая метаданные источника и его 64-байтную подпись.
|
||||
block_size для RS рассчитывается из этого бюджета; он включает 9-байтный заголовок RS seq/subblock.
|
||||
Максимальный размер части субпотока по умолчанию — 1300 байт: внешние метаданные 47 и RS до 1253 байт.
|
||||
Внутри RS находятся подписанные метаданные 55 байт, содержимое и одна 64-байтная подпись.
|
||||
block_size включает 9-байтный заголовок RS seq/subblock. Максимальная длина содержимого при 6+2 — 7345 байт.
|
||||
При длине содержимого L фактический RS-size = 9 + ceil((55 + L + 64)/k), полный размер части = 47 + RS-size.
|
||||
Например, L=1000 даёт восемь частей по 243 байта; L=7345 даёт восемь частей по 1300 байт.
|
||||
Один контекст RS принимает пачки разной длины без пересоздания матрицы; все части одной пачки равны по размеру.
|
||||
Handle получателя, поколение stream-сессии, изменяемый путь и служебные заголовки ETCP идут сверх этого бюджета.
|
||||
Не обещаем соответствия одной кодограммы одному UDP-пакету: необходимую фрагментацию выполняет ETCP normalizer.
|
||||
|
||||
На первой порции данных неполной пачки источник запускает таймер 100 мс.
|
||||
При заполнении пачка немедленно кодируется, таймер отменяется; для следующей неполной пачки начинается новый срок.
|
||||
По таймауту кодируем накопленные данные с дополнением нулями, сохраняя их действительную длину.
|
||||
По таймауту кодируем накопленные данные в минимальные части с дополнением максимум k-1 нулями.
|
||||
Действительная длина содержимого входит в подпись; подпись также защищена RS от пропусков.
|
||||
Без накопленных данных пустые пачки не создаём. При штатном окончании источник сразу сбрасывает остаток.
|
||||
Этот таймер есть только у источника; ретрансляторы не накапливают данные для повторного формирования пачек.
|
||||
|
||||
В этапе 1 ретранслятор пересылает полученные блоки; отсутствующие блоки для downstream заново не генерирует.
|
||||
Локальный decode восстанавливает содержимое для потребителя, но не создаёт подписи источника на отсутствующие блоки.
|
||||
Восстанавливаем при наличии k проверенных блоков, не ожидая остальных.
|
||||
Полученные байты выдаются как есть с удалением padding, по порядку batch_seq.
|
||||
Локальный decode восстанавливает содержимое и подпись для потребителя; отсутствующие части в кольцо не добавляются.
|
||||
Восстанавливаем при наличии k структурно допустимых частей, не ожидая остальных.
|
||||
После успешной проверки одной подписи выдаём только содержимое, без метаданных/подписи/padding, по порядку batch_seq.
|
||||
Подпись не зависит от получения определённого субблока. Неверная подпись/подписанные поля дают GAP одной пачки;
|
||||
приём следующей пачки продолжается, owner не закрывается. Повторно отвергнутая пачка не декодируется.
|
||||
Подмена отдельной части обнаруживается только после RS; определить виновную часть по общей подписи нельзя.
|
||||
Перебора альтернативных наборов и исправления неизвестных ошибок нет: RS исправляет только пропуски.
|
||||
Невосстановимый пропуск обозначается событием GAP; нельзя молча склеивать данные по обе стороны разрыва или выдавать нули за исходные байты.
|
||||
Окончательно пропускаем пачку, когда её данных уже нет в окне либо все нужные выдачи прошли её индекс/сообщили пропуск,
|
||||
а k блоков не собрано. Получение более поздней пачки от одного поставщика само по себе не закрывает ожидание остальных.
|
||||
@@ -102,20 +112,19 @@ Handle получателя, поколение stream-сессии, измен
|
||||
|
||||
4. Подпись источника и timestamp
|
||||
|
||||
Каждый полученный после RS блок, в том числе проверочный, подписывается Ed25519-ключом самого источника.
|
||||
Подписывается каноническое сообщение с маркером назначения подписи stream_block, включающее:
|
||||
group_id, source_node_id, source_epoch, параметры FEC, batch_seq, subblock, source_ts_ms,
|
||||
действительную длину содержимого пачки, флаги источника и все байты RS-кодограммы.
|
||||
Byte order и точная раскладка фиксируются в stream_proto.h. Дублирующиеся поля seq/subblock проверяются на совпадение.
|
||||
Это связывает блок с группой, запуском, индексом, временем и параметрами кодирования.
|
||||
|
||||
Подпись создаётся один раз в источнике после FEC. Она хранится с блоком и пересылается без изменений.
|
||||
Источник подписывает Ed25519 каноническое сообщение stream_batch: group_id, source_node_id, source_epoch,
|
||||
n, r, фактический RS-size, source_ts_ms, действительную длину, flags, batch_seq и все байты содержимого.
|
||||
Единственная подпись добавляется к этому сообщению до RS. Внешняя часть stream_part1 содержит копию полей
|
||||
без криптографической проверки; seq/subblock идут в RS-заголовке. Формат big-endian закреплён в stream_proto.h.
|
||||
После decode подпись проверяется по ключу источника, а подписанные поля сверяются с дескриптором и внешними подсказками.
|
||||
Неизменяемые части хранятся и пересылаются без изменения и без отдельной подписи каждого субблока.
|
||||
Handle, stream-сессия и hop-list находятся вне подписанного тела, поскольку меняются при выдаче и ретрансляции.
|
||||
Перед помещением нового блока в кольцо, FEC или ретрансляцией проверяется подпись по ключу источника
|
||||
из проверенной записи мембера данной группы. Ключ непосредственного поставщика не заменяет ключ источника.
|
||||
Неверная подпись, неизвестный ключ или конфликт метаданных — отказ с диагностикой, без изменения индекса наличия.
|
||||
Для одинакового уже проверенного блока допустимо повторно не выполнять crypto, только если совпадает всё неизменяемое тело.
|
||||
Одинаковый индекс с другим содержимым нельзя считать обычным дубликатом без проверки.
|
||||
Перед помещением части в кольцо проверяются формат, границы размеров, канонический размер и согласованность полей пачки.
|
||||
Части могут пересылаться до сборки всей пачки, сохраняя малую задержку; они ещё не подтверждены ключом источника.
|
||||
Содержимое для приложения допускается только после проверки подписи по ключу из принятой записи мембера данной группы.
|
||||
Ключ непосредственного поставщика не заменяет ключ источника. Неверная подпись, неизвестный ключ или конфликт логируются.
|
||||
При отвергнутой пачке логируются выбранные субблоки и их поставщики; приложение получает GAP и продолжает работу.
|
||||
Дубликатом считается только побайтовое совпадение всей части. Тот же индекс с другим содержимым — конфликт.
|
||||
|
||||
source_ts_ms = (uint16_t)monotonic_time_ms источника в момент формирования пачки.
|
||||
У всех её субпотоков одинаковые timestamp, длина и флаги. Ретранслятор не переписывает их своим временем.
|
||||
@@ -130,11 +139,13 @@ Timestamp циклический с периодом 65536 мс; обычный
|
||||
|
||||
5. Кольцевой буфер и единственный способ выдачи
|
||||
|
||||
На экземпляр — 32 * 1024 * 1024 байт под неизменяемые блоки всех субпотоков вместе, включая их подписи.
|
||||
На экземпляр — 32 * 1024 * 1024 байт под неизменяемые части всех субпотоков вместе.
|
||||
Слоты резервируются по максимальному размеру; меньшие части уменьшают трафик/работу RS, но не размер массива слотов.
|
||||
stored_bytes и логическая очередь выдач учитывают фактические длины. Вытеснение ограничено числом зарезервированных слотов.
|
||||
Метаданные индекса, путей и сборки учитываются отдельно и ограничиваются.
|
||||
Буфер общий для локального потребителя и всех downstream; копии кольца на каждого получателя не создаются.
|
||||
Источник сначала помещает сформированные блоки в своё кольцо, затем делает их доступными выдачам.
|
||||
Ретранслятор сначала проверяет и сохраняет блок, затем планирует выдачу подписчикам.
|
||||
Ретранслятор сначала проверяет формат и сохраняет часть, затем планирует выдачу подписчикам.
|
||||
|
||||
Индекс записи — (batch_seq, subblock) внутри конкретной эпохи.
|
||||
Новые пачки вытесняют старейшие; при вытеснении пачки удаляются все её блоки и метаданные.
|
||||
@@ -194,7 +205,7 @@ ETCP обеспечивает переповторы, порядок, мульт
|
||||
- SUBSCRIBE/ACCEPT/REJECT — непрерывная выдача с индекса либо последнего доступного блока.
|
||||
- RENEW — продление списка существующих выдач, период 2 секунды.
|
||||
- UNSUBSCRIBE/CLOSED — закрытие выдачи с указанием handle и причины.
|
||||
- DATA/GAP/EXPIRED — подписанный блок либо уведомление о пропуске.
|
||||
- DATA/GAP/EXPIRED — часть подписанной RS-пачки либо уведомление о пропуске.
|
||||
- OVERLOAD — запрос сокращения исходящей нагрузки через закрытие нескольких выдач.
|
||||
- REVERSE_REQ — встречное NCD-подключение через маршрутизатор группы.
|
||||
- END — последняя пачка и штатное завершение содержимого источником.
|
||||
@@ -229,7 +240,7 @@ ACCEPT содержит handle, фактический начальный инд
|
||||
которая ждёт первый блок; первый проверенный DATA по-прежнему устанавливает общий N.
|
||||
Пустой ретранслятор пути не объявляет. Завершение без данных подтверждается подписанным END с last_seq=UINT64_MAX.
|
||||
Отказы различают отсутствие подписки/трансляции, эпоху, FEC, позицию, слот, перегрузку, цикл и право доступа.
|
||||
DATA содержит поколение сессии, handle, неизменяемый подписанный блок источника и изменяемый путь.
|
||||
DATA содержит поколение сессии, handle, неизменяемую часть RS-пачки и изменяемый путь.
|
||||
Источник подписывает и END с ключом трансляции и индексом последней пачки, чтобы ретранслятор не мог подделать окончание.
|
||||
|
||||
Нет продления 6 секунд — отправитель закрывает выдачу и сообщает CLOSED, при необходимости через маршрутизатор группы.
|
||||
@@ -476,12 +487,12 @@ Stop/destroy выполняются по правилам ядра, вне callb
|
||||
Проверки:
|
||||
- Несколько подписок/источников/групп на одном ETCP; stop одной сохраняет остальные и чужое владение.
|
||||
- Неподписанный узел не создаёт экземпляр, не выполняет crypto/FEC для DATA и не ретранслирует его.
|
||||
- Источник задаёт различные FEC; decode из k проверенных блоков и невозможность при k-1.
|
||||
- Подпись каждого исходного/проверочного блока; подмена payload/timestamp/индекса/FEC/эпохи/группы отвергается.
|
||||
- Кодограммы около 1300 байт, полный/неполный буфер, источник сбрасывает за 100 мс, ретранслятор не имеет такого таймера.
|
||||
- Источник задаёт различные FEC; decode и проверка одной подписи из k частей, невозможность при k-1.
|
||||
- Подпись внутри RS; подмена payload/подписи/timestamp/индекса/FEC/эпохи/группы не выдаётся приложению; следующий индекс принимается.
|
||||
- Части до 1300 байт, чередование малых/полных пачек, максимум k-1 padding; байтовый источник сбрасывает за 100 мс.
|
||||
- Оборот timestamp, нулевая дельта, постепенное отставание, догон, полная остановка и длинный разрыв без ложного числа оборотов.
|
||||
- Переполнение 32-МБ кольца, дырки, EXPIRED до отправки, курсор медленного получателя и ограниченность памяти.
|
||||
- Первый подписанный блок с конца задаёт общий N; остальные выдачи начинают с него, а не с независимых концов.
|
||||
- Первая допустимая часть с конца задаёт общий N; остальные выдачи начинают с него. READY требует восстановленной проверенной пачки.
|
||||
- Идемпотентные запросы/продления/закрытия, водяной знак handles, поздние сообщения, REINIT и новая эпоха источника.
|
||||
- Reverse/неуспех/отмена; потеря одного линка сохраняет выдачи, DOWN всего NCD запускает восстановление.
|
||||
- Перекрытие поставщиков без дублирования потребителю, rollback, одновременное восстановление нескольких субпотоков.
|
||||
@@ -506,9 +517,9 @@ Stop/destroy выполняются по правилам ядра, вне callb
|
||||
Реализация начата 10.10.2026. Работа разбита на проверяемые этапы:
|
||||
|
||||
[+] Основа данных в src/stream:
|
||||
stream_proto.h — канонический big-endian формат подписанного блока; дефолтный полный блок 1300 байт.
|
||||
stream_block — RS и Ed25519-подпись каждого блока; проверка ключа трансляции, параметров и содержимого.
|
||||
stream_buffer — общий бюджет 32 МБ по фактически сохранённым блокам, индекс пачек и вытеснение старейшей пачки.
|
||||
stream_proto.h — канонический формат частей до 1300 байт и подписанной пачки внутри RS.
|
||||
stream_block — переменный размер RS и одна Ed25519-подпись пачки до кодирования; проверка после восстановления.
|
||||
stream_buffer — 32 МБ слотов, фактические длины данных/очереди, индекс пачек и вытеснение старейшей пачки.
|
||||
stream_metrics — относительное отставание, rate, timestamp wrap/reset и минутная история проблем/остановок.
|
||||
stream_source — приём непрозрачных байтов, немедленная выдача полной пачки, таймер остатка 100 мс и отмена при destroy.
|
||||
Добавлены категория stream, Autotools-сборка и test_stream_core.
|
||||
@@ -651,7 +662,7 @@ Stop/destroy выполняются по правилам ядра, вне callb
|
||||
|
||||
Все stream-числа на wire — big-endian, без packed-структур и зависимости от host byte order.
|
||||
Версия stream wire — 4; обратная совместимость не поддерживается.
|
||||
Заголовок raw (52 байта): cmd:1, version:1, command:1, subblock:1,
|
||||
Заголовок raw (52 байта, version=5): cmd:1, version:1, command:1, subblock:1,
|
||||
group_id:8, source_node_id:8, source_epoch:8, sender_epoch:8, receiver_epoch:8, handle:8.
|
||||
INFO_REQ/RESP согласуют sender/receiver epochs; receiver_epoch=0 используется INFO_REQ для обнаружения поколения и REVERSE_REQ.
|
||||
Подписанный routed payload содержит тот же заголовок; его group_id сверяется с реальной группой router,
|
||||
@@ -670,7 +681,7 @@ bit3 — CPU известен, bit4 — кольцо непусто для эт
|
||||
SUBSCRIBE: requested_seq:8; REJECT: reason:1, для SUBSCRIBE дополнительно first_available:8,last_available:8,
|
||||
для INFO дополнительно probe_nonce:8. Старый nonce не подтверждает новую пробу.
|
||||
RENEW: один header handle без payload (каждая кодограмма продлевает один элемент списка).
|
||||
UNSUBSCRIBE/CLOSED: reason:1. DATA: path_count:1,node_ids:8*path_count,неизменяемый подписанный блок.
|
||||
UNSUBSCRIBE/CLOSED: reason:1. DATA: path_count:1,node_ids:8*path_count,неизменяемая часть RS-пачки переменной длины.
|
||||
GAP: old_cursor:8,next_cursor:8, уведомление включает диапазон [old_cursor,next_cursor).
|
||||
END: "stream_end":10,group_id:8,source_node_id:8,source_epoch:8,last_seq:8,Ed25519:64 — всего 106 байт.
|
||||
UINT64_MAX в END означает пустой источник; принимается только выдачей с next=0 и без ранее принятых DATA.
|
||||
@@ -728,7 +739,7 @@ Restart в той же source_epoch сохраняет consumer cursor: bootstra
|
||||
смешивание отвергается до изменения данных. stream_publish_finish не освобождает буфер источника.
|
||||
|
||||
Медиаблок uAV1 находится целиком внутри входа RS, поэтому header восстанавливается вместе с данными.
|
||||
При штатных 6+2 полный медиаблок <=7080 байт. Раскладка big-endian, без packed-структур:
|
||||
При штатных 6+2 полный медиаблок <=7345 байт. Раскладка big-endian, без packed-структур:
|
||||
|
||||
fixed header (32 байта):
|
||||
magic="uAV1":4, video_codec:1, audio_codec:1, video_count:1, audio_count:1,
|
||||
|
||||
Reference in new issue
Block a user