## 2023-10-22 тестируем шифрование на уровне протокола ## 2023-10-21 тестируем substituter ## 2023-10-12 ... PR: hbs2-file-logger branch: fastpok-file-logger commit: e411e292461179a83a5fc0a0d78f98233c7323f9 Добавлена возможность писать логи в файл. ## 2023-10-11 запостили аннотацию с ключами. теперь пробуем её процессировать. и вот этот волнующий момент ... тестируем, как работает удаление ключа. - не работает пока что (почему?) ... и еще раз тестируем удаление/добавление ключей ## 2023-10-10 Начинацию операем. Шаг 1. Выяснить, что нам вообще надо добавить нового автора ## 2023-10-08 Конечно, грустно, что девлог превратился в черти-что. С другой стороны, его можно вывести на новый уровень, положив начало dashboard-у. Продолжаем отлаживать странную проблему, когда гит выводит новые референсы только со второй попытки. ## 2023-10-05 что такое опять Ага! FIXME: empty-pushed-dont-work похоже, "пустые" пуши без содержимого не приводят к обновлению стейта ## 2023-09-25 ## 2023-14-08 PR: hbs2-git-config-location branch: hbs2-git-fastpok commit: 82d5a30f4510b3f70bfbf2bc208b14df4ce2b17d Изменено расположение файла конфигурации hbs2-git, незначительный рефакторинг. ## 2023-07-30 какие-то косяки ## 2023-07-25 кажется, git push --force что-то портит ## 2023-06-03 WTF? ## 2023-06-23 Странно, но всё еще новый формат репозитория. Вроде бы сегодня можно попробовать его смержить в мастер. Совместим со старым он не будет ## 2023-04-26 тестируем новый формат репозитория. получится ли запустить его одновременно со старым? вопрос. Потенциально, можно делать инкрементальные добавления в файл лога гита + так же нужно добавить запись "последняя запись". Но тогда эту последнюю запись невозможно будет добавлять, так как лог append-only. Можно её добавить только при передаче через TCP стрим, что бы как-то определять конец файла. Тест. ## 2023-04-18 что-то сломано ## 2023-04-05 FIXME: refactor-crypto-remove-l4-protocol-dependency Удалить нерелевантную зависимость от транспортного протокола в криптографии и зарефакторить все ссылки. ## 2023-04-04 FIXME: hbs2-peer-send-does-not-save-transaction При посылке транзации через hbs2-peer он не сохраняет её сам у себя. Это уже привело к коллизии. ## 2023-04-03 TODO: hbs2-peer-meidan-rtt вычислять и выводить медианный rtt вместо последнего PR: hbs2-peer-meidan-rtt branch: calculate-median-rtt commit: a9874a5727c3c16eb37e01b39832a4dfd3418c9c Вычисление и отображение медианного RTT вместо последнего. ## 2023-04-01 TODO: hbs2-peer-dump-wip-blocks TODO: hbs2-peer-del-block-from-wip ## 2023-03-29 TODO: smart-peer-choice-on-download TODO: test-new-timeouts-on-good-network TODO: measure-peer-rtt-on-ping TODO: set-timeouts-dynamically-via-rtt TODO: ASAP-FIX-FUCKING-AUTH-LOST-WTF ## 2023-03-28 FIXME: git-repo-consistency-check ## 2023-03-27 PR: gettime-non-linux branch: pr-gettime-non-linux commit: a2cd4d575f965dc9c71b69a1355d6603129f2373 Исправляет получение текущего времени для MacOS. Также добавлены "x86_64-darwin" и "aarch64-darwin" во flake.nix. ## 2023-03-27 TODO: lesser-ping-period TODO: reliable-storage-write TODO: http-block-download-worker FIXME: atomic-ref-update FIXME: ref-download-monitor FIXME: git-clone-check-whole-tree FIXME: memory-usage-on-big-repos FIXME: slow-on-big-repos ## 2023-03-27 FIXME: atomic-ref-update FIXME: ref-download-monitor FIXME: git-clone-check-whole-tree FIXME: memory-usage-on-big-repos FIXME: slow-on-big-repos ## 2023-03-26 FIXME: download-log-location-again TODO: git-http-protocol Протокол http для гита, что бы можно было ссылаться на репозиторий например в nix flakes. TODO: hbs2-websockets-transport http, т.к. неясно, к каким доменам привязывать https. Посылать (и принимать) наши датаграммы. Соединения время от времени рвать и переподключаться (?). Таймаут задавать в конфиге. Поскольку у нас потоки на каждого пира, удобно будет сделать вебсокетные потоки на каждого пира, и в них делать всё. В потоке определять время жизни и т.п. Нужно будет определить messaging для вебсокетов? TODO: git-tags-support FIXME: macos-support-clock -- CPP -- | Use coarse clock timer. This timer has 1ms resolution but is much -- faster comparing to the ordinary one. Is used on linux, on macos -- provides ordinary one. getTimeCoarse :: IO TimeSpec #ifdef linux_HOST_OS getTimeCoarse = getTime MonotonicCoarse #else getTimeCoarse = getTime Monotonic #endif ## 2023-03-24 проверка: wip109 TODO: storage-reliable-write Надёжную процедуру записи блока. Вариант 1: - пишем на tmp - проверяем hash - переименовываем Вариант 2: - пишем на имеющуюся файловую систему под уникальным именем - переименовываем Если переименование провалилось --- можно потом попробовать сделать это повторно. Временные файлы не удаляются, пока запись 100% не удалась. FIXME: storage-check-utility Искать блоки, у которых hash не соответствует контенту. Писать в лог. Пытаться скачать и перезалить такие блоки. FIXME: git-does-not-show-update-after-push git должен печатать то, что он закоммитил, после push, однако не пишет. А git push+fetch --- пишет. [dmz@minipig:~/w/hbs2]$ git push hbs2 importing objects [=========================] 100% calculate dependencies storing dependencies [======================] 100% store objects [=============================] 100% head: 9fJkmR61qUPZdrkEYpEWPQna2Bk6oaepofK5ZjJQHxrF merkle: GpHhNxwSLcvMt2rYRx2TLdxwFH4mhUrjonAs8WPnJuC2 Everything up-to-date importing objects [=========================] 100% FIXME: weird-reflog-syncronization-delays Долгое время не обновляется reflog, при том, что все транзации в БД есть. Нужно исследовать проблему при её повторении. FIXME: repeated-zero-block-size-issue Регулярно повторяется проблема с блоками размера 0. Возможно, есть блоки, хэш которых не соответствует контенту. TODO: calculate-hash-only-once Вычислять блок только один раз в фунции записи блока. То есть, при приходе блока звать putBlock и разбирать его ответ. Интерфейс, получается, становится ``` putBlock :: Storage -> Block -> Either Code Hash ``` TODO: storage-data-compression Сжимать данные в storage. Вызывает много вопросов, хэш сжатого блока перестаёт соответствовать исходному контенту. Если перед передачей блок распаковывать, что бы на принимающией стороне хэш соответствовал --- то это бред. Если не распаковывать, то хэш не сойдется. Выходом является, кажется, передача признака, что блок сжат, либо же проверка что пришло, определение, что блок был сжат, и распаковка. Это можно сделать, в принципе, в storage, путем оборачивания блока в какой-то конструктор, который будет пытаться разобрать storage. Тогда надо проверку хэша блока делать в storage. Тогда надо отличать ситуацию, когда мы не смогли записать блок от ситуации, когда не сошёлся хэш. Это меняет интерфейс записи, кроме того, что делать с асинхронной записью (enqueue?) Не пора ли разбивать девлог на куски, хоть его никто кроме меня и не пишет? ## 2023-03-23 TODO: ref-block-download-monitor нужно сделать решение, которое для блока будет сообщать его текущий статус (сколько скачано, сколько осталось). Следует отметить, что при приходе большого дерева мы можем не знать, сколько там осталось, особенно учитвая, что там могут быть и зависимости тоже. Думали, что UDP не работает. А он еще как работает. Отлаживаем pusp, wip92 NOTE: subscribe-reflog-format ;; subscribe: fetch reflog value on start poll-default reflog 10 ;; time in minutes ;; говорит, что надо опрашивать ссылку раз в указанный период ;; в минутах poll reflog 1 "2YNGdnDBnciF1Kgmx1EZTjKUp1h5pvYAjrHoApbArpeX" poll reflog 2 "4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo" ; говорит, что мы в принципе слушаем ссылку такую-то subscribe reflog "2YNGdnDBnciF1Kgmx1EZTjKUp1h5pvYAjrHoApbArpeX" subscribe reflog "95mSAkUqyrkM47eBu6jXnHZW97nxARKZfuKpj4vxR8rF" subscribe reflog "4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo" subscribe reflog "74Kxc6kYCnjuXg7ridb28gE4n2vzSaKEm9MZNqd9ACV9" ; слушать все рефлоги subscribe reflog * ; реализовать подписку на рефлоги только от такого-то пира! ; subscribe reflog from-peer XXX FIXME: asap-storage-fails-investigation Появляются блоки с размером 0 и правильным названием (соответствует хэшу). Видимо, каким-то образом не успевают записаться. Необходимо проверить storage под нагрузкой раз, реализовать более устойчивый к ошибкам алгоритм записи - два, проверить его оверхед относительно основного сторейджа - три. Так же надо реализовать какой-то метод контроля целостности и стратегию при обнаружении ошибок: например, отдельный процесс, который берёт случайный блок, читает его, если хэш расходится, то: 1) сигнализирует об ошибке 3) удаляет?? 4) отправляет скачиваться и помечает блок, как к перезаписи. ## 2023-03-22 Или нет затыков? wip91 Какие-то затыки. wip26 FIXME: ошибка-десереализации-при-удалении-бранча [root@hbs2-test:~/hbs2]# git fetch git-remote-hbs2: DeserialiseFailure 0 "end of input ## 2023-03-21 TODO: hbs2-peer-poll-reflog poll-reflog-default - стартует процесс, который с заданной периодичностью (или дефолтной) запрашивает рефлог у всех, кого знает. TODO: hbs2-peer-subscribe-reflog Опция, subscribe-reflog Если включена, пир слушает данный reflog. Если * - то слушаются все рефлоги. Если reflog-from-peer "peer" reflog" - делает так, кто рефлог X принимается только от данного пира. Если * - то все рефлоги от пира. FIXME: невнятно-ругается-когда-выключен-http невнятно ругается, когда выключен http у hbs2-peer. нужно отчётливо говорить, что включите http. FIXME: ASAP-hardcoded-master-when-no-master Как видно ниже -- в исходном репозитории нет бранча master, однако, операция чтения ссылки его вернула, отсюда поломан git clone. Решение: надо проверять, что этот бранч существует, если его нет --- то брать один из бранчей, которые есть в конфиге и существуют, иначе те, котрые существуют [trace] head read: GKqqzjz3wr81hDf6gjYXLLp49PuUqwtcUqSNwMpwim4C [===========================================] 100% [trace] sendLn "@refs/heads/master HEAD" [trace] sendLn "97bed303895cd4200b53230ba9c244215aa80beb refs/heads/hbs2-git" [trace] got reflog (3, 6e1bQr8mvzn5xbdfRRtEiZJq8xDb58Tyz52hvKvoLNCK) [trace] ABOUT TO UPDATE HEAD [trace] [fetch, 0000000000000000000000000000000000000000, refs/heads/master] [trace] fetch 0000000000000000000000000000000000000000 refs/heads/master [trace] [fetch, 97bed303895cd4200b53230ba9c244215aa80beb, refs/heads/hbs2-git] [trace] fetch 97bed303895cd4200b53230ba9c244215aa80beb refs/heads/hbs2-git [trace] [] [trace] dbPath: /home/dmz/.local/share/hbs2-git/4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo [trace] updateLocalState 4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo [trace] hbs2 reflog get 4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo [trace] "FcctCWH8hTESQmnb8ozCmXhKW1SXzLbmY9ocCyU1TxEr\n" [trace] FcctCWH8hTESQmnb8ozCmXhKW1SXzLbmY9ocCyU1TxEr warning: remote HEAD refers to nonexistent ref, unable to checkout [dmz@expert:~/tmp]$ hbs2 cat GKqqzjz3wr81hDf6gjYXLLp49PuUqwtcUqSNwMpwim4C @refs/heads/master HEAD 97bed303895cd4200b53230ba9c244215aa80beb refs/heads/hbs2-git REVIEW: fastpok-preved-2 REVIEW: faspok-preved FIXME: THAT-PEER-IS-JERK-issue Повторяется ситуация, когда приходит пакет с размером 0. Надо, во первых, понять почему. Во вторых - как с этим бороться. В третьих - как в этой ситуации перестать бомбить себя и пира. TODO: hbs2-fetch-reflog-does-not-work Похоже, что проигрывание транзакций не вызывает скачивание зависимостей. TODO: hbs2-peer-poll-reflog poll-reflog-default - стартует процесс, который с заданной периодичностью (или дефолтной) запрашивает рефлог у всех, кого знает. TODO: hbs2-peer-subscribe-reflog Опция, subscribe-reflog Если включена, пир слушает данный reflog. Если * - то слушаются все рефлоги. Если reflog-from-peer "peer" reflog" - делает так, кто рефлог X принимается только от данного пира. Если * - то все рефлоги от пира. FIXME: невнятно-ругается-когда-выключен-http невнятно ругается, когда выключен http у hbs2-peer. нужно отчётливо говорить, что включите http. FIXME: ASAP-hardcoded-master-when-no-master Как видно ниже -- в исходном репозитории нет бранча master, однако, операция чтения ссылки его вернула, отсюда поломан git clone. Решение: надо проверять, что этот бранч существует, если его нет --- то брать один из бранчей, которые есть в конфиге и существуют, иначе те, котрые существуют [trace] head read: GKqqzjz3wr81hDf6gjYXLLp49PuUqwtcUqSNwMpwim4C [===========================================] 100% [trace] sendLn "@refs/heads/master HEAD" [trace] sendLn "97bed303895cd4200b53230ba9c244215aa80beb refs/heads/hbs2-git" [trace] got reflog (3, 6e1bQr8mvzn5xbdfRRtEiZJq8xDb58Tyz52hvKvoLNCK) [trace] ABOUT TO UPDATE HEAD [trace] [fetch, 0000000000000000000000000000000000000000, refs/heads/master] [trace] fetch 0000000000000000000000000000000000000000 refs/heads/master [trace] [fetch, 97bed303895cd4200b53230ba9c244215aa80beb, refs/heads/hbs2-git] [trace] fetch 97bed303895cd4200b53230ba9c244215aa80beb refs/heads/hbs2-git [trace] [] [trace] dbPath: /home/dmz/.local/share/hbs2-git/4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo [trace] updateLocalState 4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo [trace] hbs2 reflog get 4qjsu7y5umqfFQG978nEUZCHJwd1ZSKrNT5Z74G7tbdo [trace] "FcctCWH8hTESQmnb8ozCmXhKW1SXzLbmY9ocCyU1TxEr\n" [trace] FcctCWH8hTESQmnb8ozCmXhKW1SXzLbmY9ocCyU1TxEr warning: remote HEAD refers to nonexistent ref, unable to checkout [dmz@expert:~/tmp]$ hbs2 cat GKqqzjz3wr81hDf6gjYXLLp49PuUqwtcUqSNwMpwim4C @refs/heads/master HEAD 97bed303895cd4200b53230ba9c244215aa80beb refs/heads/hbs2-git FIXME: THAT-PEER-IS-JERK-issue Повторяется ситуация, когда приходит пакет с размером 0. Надо, во первых, понять почему. Во вторых - как с этим бороться. В третьих - как в этой ситуации перестать бомбить себя и пира. Тест git push 6 ## 2023-03-20 Тест git push 4 TODO: clone-no-ref-situation Проверить, как работает git clone, если на хосте не скачано состояние ссылки, или данные подъехали не полностью. (Как вообще этого добиться? Нужно вычислять состояние ссылки) TODO: git-import-before-fetch TODO: git-export-on-push TODO: reflog-state-request TODO: git-new-repo-convenience-function ## 2023-03-19 FIXME: broken-commit-object-file-disaster see 13CuHGmVHfdr2VAzmnMkQV4kZa8kSM2HEoSb8dUVLSQV FIXME: ASAP-fix-download-log 8e72fbff5c395fa6d1dab02dde7eea887bdca274 ## 2023-02-28 TODO: hbs2-git - git push hbs2:// - git fetch hbs2:// - git clone hbs2:// - подпись объектов - проверка подписей объектов - задание ACL для репозитория - объекты git - изменение ref FIXME: annoying-lost-peer-auth-message кэшировать данное событие в peer loop на какое-то время и больше не ныть. Вообще, поток должен отстреливаться, если его нет в known-peers TODO: gc-live-mem-stat Выводить в лог размер активной памяти TODO: cache-purge-loop выросло количество потребляемой памяти, скорее всего, нужно чистить кэши в тредах и в DownloadEnv. ## 2023-02-27 В целом ясно, что нужно пересмотреть работу с очередью: скачивание огромных объемов при небольшом количестве пиров забивает её целиком, и другие каналы не будут синхронизированы, пока не будет выкачан большой объем данных. Это дорога к DDoS атаке и полной остановке сервиса --- можно рассылать огромные файлы и забивать очередь. Для борьбы с этим, кажется, необходима либо рандомизация очереди (как?), либо введение приоритетной очереди, и приоритет ставить в обратную зависимость от глубины (высоты) дерева и размера merkle-tree блока, либо же понижение приоритета выкачивания для "больших" пакетов. Вместе с тем, нам очевидно, нужен мониторинг скачивания референса/блока. Какое видится решение: Отдельная очередь на каждый fetch/announce. Качаем, порциями забрасывая пакеты в общую очередь и запоминая, что забросили. На каждый скачанный блок мы подписываемся на уведомление, кроме того, вешаем монитор. По уведомлению --- вычеркиваем блок. По монитору --- проверяем, сколько блоков осталось. Можно при анонсе/фетче парсить пришедший блок и запоминать число невыкачанных блоков. Тогда при каждом событии, что блок скачан - мы уменьшаем это число, что даёт нам возможность мониторить прогресс. Когда это число достигает 0, мы запускаем процессинг опять, удостовериваемся, что всё выкачано и если да --- то можем уведомить о том, что блок скачан (и удаляем процесс). FIXME: e5bd-download-stuck-on-big-volumes Скачивание затыкается при большом объеме передаваемых данных и длительном времени работы, т.е на медленном канале. с чем конкретно это связано, пока что непонятно. Кажется, что это может быть связано с потерей пакетов, т.е очередь на скачивание пустеет, тогда как блоки еще не выкачаны. Необходимо проверить это в первую очередь. 1. Пока нет счётчиков, добавить trace в цикл работы с очередью 2. Добавить debug на размер очереди (пустая/не пустая) Возможно, происходящее связано с неатомарностью обновления счётчиков/wip и самой очереди, хотя то, что закачка фактически прекращается, а данные очевидно не выкачаны --- говорит нам о потере самих блоков для скачивания. Куда они могут теряться в принципе? Есть место в алгоритме, где блоки не возвращаются в очередь? ## 2023-02-26 TODO: block-shuffle Если при добавлении перемешивать блоки, то есть надежда, что пиры скачают их в разном порядке и будут помогать друг другу. Но при этом может оказаться сломан стриминг (когда/если он будет) TODO: choose-peer-lesser-rtt Выбирать пира с наименьшим RTT при скачивании TODO: peer-rtt-stats 1. Считать скользящее среднее (?) для нетяжелых запросов 2. Окно фиксированного размера 3. Усреднять / брать медиану 4. Сделать подсчёт для произвольных запросов TODO: smarter-block-download 1. Узнавать размер блока как можно раньше 2. Не запрашивать размер блока в том же цикле, что и скачивание 3. Хранить информацию о размера блока в статусе блока 4. Хранить информацию о пирах, которые ответили -- в статусе блока 5. Выбирать только пира, который сказал размер ## 2023-02-25 FIXME: asap-whitelist Реализовать whitelist. Поведение: если whitelist не пустой --- авторизовать только пиров, которые находятся в нём. В остальном (настройки) аналогично blacklist. Нужно для отладки fetch-from-single-peer-speed-degradation #asap FIXME: fetch-from-single-peer-speed-degradation Упала скорость скачивания в случае одного пира на раздаче. Возможно, дело в новом алгоритме (ban), это означает его неправильную работу. Вероятно, проблема в том, что треды пиры, которые не имеют блоков - забирают их себе и не отдают какое-то время, что влияет на скорость докачки хвостов. Как с этим быть --- пока непонятно. Если убрать этот механизм, то возникнет busyloop. TODO: counters-and-metrics UPD. просто внедрить ekg Сделать механизм счётчиков и измерений на их основе. Идея такая: счётчик заводится и каким-то образом изменяется ( в зависимости от типа ). Наиболее вероятные типы: Integer, Double. Некий процесс производит измерения счётчиков в зависимости от их типа/настроек. Например, средее за период. Скользящее среднее. Изменение за период времени (TBD). Счётчики могут быть доступны как в логе, так и удалённо (RPC), для целей отладки. Простейшее примение: watchdog. Смотрим на некую величину, если она не меняется некоторое время (например, между двумя запросами) --- следовательно, произошла авария и нужно рестартовать сервис и/или рапортовать об этом. Что бы не таскать счётчики по монадам/публичным интерфейсам, можно поступить с ними аналогично тому, как сделаны логи. Счётчики должны быть максимально возможно быстрые и вносить минимальные задержки в работу программы. Задача разбивается на несколько частей: 1. Счётчик, показывающий текущиее состояние. Пример, текущее значение потребления RAM. Или текущее количество запросов. 2. Измерение, т.е некий процесс, который с заданной периодичностью смотрит значение счётчика и что-то с ним делает: например, считает скользящее среднее или экспоненциальное среднее. 3. Вывод информации о счётчиках (Лог? RPC?) 4. Анализ информации о счётчиках Пример, зачем нужен счётчик: введём подпротокол для измерения RTT, для использования в алгоритме Congestion Control. Еще пример, зачем нужен счётчик: заводим в каждом процессе, который подозревается на наличие busyloop. Смотрим скорость изменения счетчика. Если она больше некоторого порога, определяемого периодичностью процесса, следовательно, у нас busyloop. Можно определять эти busyloop даже без явно заданного порога, просто глядя на график от времени и обнаруживая аномалии. Порядок реализации: 1. драфт дизайна, включающий примеры использования 2. обсуждение 3. реализация возможно, есть что-то готовое/полуготовое. Во всякий там прометеус/графану и прочее подобное я не верю. Но даже если и есть годное, можно адаптировать. Счётчики это типичные временные ряды, можно их складывать в ClickHouse. Опять же, у нас нет цели поддерживать/мониторить целую огромную инфраструктуру отрядом девопсов. Цели две: отладка и реализация watchdog-ов, т.е нода должна сама, своими силами анализировать счётчики и как-то справляться с аномалиями. То есть: пир состоит из двух (или чуть больше) независимых (forkOS) потоков, один из которых делает работу, второй смотрит за первым, и рестартует его, если надо. Отдельно можно анализировать снапшоты данных метрик и скармливать их в BDD, что бы строить деревья принятия решений: нормальная ситуация, или требуется загасить/перезапустить ноду, или же речь вообще идёт о DDoS атаке и надо обороняться --- банить каких-то пиров, например. FIXME: blocks-wip-inconsistency Иногда показывает blocks.wip не равный 0, когда блоки в действительности скачаны. BlockDownload, PeerTypes FIXME: verbose-debug-log Сделать новую секцию для слишком вербозных сообщений. Сделать динамическую установку уровня логгирования пира. FIXME: faster-download-log-append Сейчас запись о fetch/announce попадает в download-log раз в 300 секунд, когда он разгребается. Нужно, что бы писалось чаще, на случай, если потребуется восстановление после падения пира. TODO: optional-rpc-parameter Сделать параметр -r hbs2-peer опциональным. Если peer только один (по умолчанию), либо если указан конфиг --- брать значение из конфига. ## 2023-02-24 TODO: persistent-download-queue На любой fetch или полученный announce: добавлять запись в download-log При старте и потом периодически: - читать download-log - сортировать уникальные - отфильтровывать успешно скачанные - остаток писать обратно в лог - не скачанные --- добавлять на скачивание Судя по всему, synthing использует и UPnP и NAT-PMP: ``` 27 11.934390497 192.168.1.43 → 192.168.1.1 NAT-PMP 44 External Address Request 28 11.934604658 192.168.1.43 → 239.255.255.250 SSDP 209 M-SEARCH * HTTP/1.1 29 11.934614907 192.168.1.43 → 239.255.255.250 SSDP 209 M-SEARCH * HTTP/1.1 30 11.938139707 192.168.1.1 → 192.168.1.43 NAT-PMP 60 External Address Response 31 11.988574699 192.168.1.1 → 192.168.1.43 SSDP 484 HTTP/1.1 200 OK 32 11.988654078 192.168.1.1 → 192.168.1.43 SSDP 484 HTTP/1.1 200 OK 33 22.058958324 192.168.1.43 → 192.168.1.1 NAT-PMP 54 Map TCP Request 34 22.094353030 192.168.1.1 → 192.168.1.43 NAT-PMP 60 Map TCP Response 35 22.094739134 192.168.1.43 → 192.168.1.1 NAT-PMP 44 External Address Request 36 22.097686421 192.168.1.1 → 192.168.1.43 NAT-PMP 60 External Address Response 37 30.007466914 192.168.1.1 → 239.255.255.250 SSDP 452 NOTIFY * HTTP/1.1 38 30.007466974 192.168.1.1 → 239.255.255.250 SSDP 524 NOTIFY * HTTP/1.1 39 30.007508252 192.168.1.1 → 239.255.255.250 SSDP 461 NOTIFY * HTTP/1.1 ``` но оно откуда-то сразу узнает default gateway. Еще про поиск gateway. Если gateway не откликается на команды PCP, NAT-PMP и UPnP (SSDP) то и искать его бессмысленно, нам неважно, где он сидит. Таким образом, мы можем просто искать его по этим протоколам: 1. Для NAT-PMP перебирать известные IP адреса и слать им пакет "\x00\x00", ждать что ответят 2. Для PCP - сделать Service discovery 3. Для UPnP (SSDP) --- сделать M-SEARCH. Самое простое и перспективное на первом этапе. Краевой случай --- откликнулось несколько роутеров. Что с этим делать --- пока непонятно. TODO: libpcp-gateway-detection Посмотреть, как libpcp ищет шлюз. TODO: gateway-detection Пытаться обнаружить UPnP gateway что бы просить у него пробросить порт. Обычно это SOHO роутер, где может функционировать NAT-PMP или UPnP. Если это модный домашний роутер типа Keenetic, там, скорее всего, будет и то, и другое. Если это что-то не очень модное (Mac), то там может быть только NAT-PMP и мы не найдем сам gateway методом UPnP. Что нам остаётся: 1. Пытаться обнаружить его через PCP Discovery 2. Взять системный Gateway из выхлопа команд (ifconfig, ipconfig и т.п) 3. Взять адрес gateway из конфига 4. Задавать команду поиска Gateway тоже в конфиге (может быть проблематично) В случае поиска через UPnP да и в любом вообще случае --- мы не можем быть уверены, что это вообще наш gateway, через который мы ходим в интернет. Это может быть какая-то L3 топология с цепочкой роутеров, тогда нас, скорее всего, ждёт провал. Мы видим, однако, что узел каким-то образом всё равно в таком случае работает, только почему-то не добавляется в PEX (расследовать). Вероятно, алгоритмы NAT приоткрывают дырку очень ненадолго. Таким образом, мы видим, что задача поэтапная и хорошего решения нет, любое вызывает какие-то проблемы. Таким образом, в первом приближении предлагается пойти по пути Syncthing: 1. Найти какой-то роутер по SSDP: ``` M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: "ssdp:discover" MX: 2 ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1 ``` 2. Попросить его открыть порты (по NAT-PMP) Если мы попросим открыть порты по NAT-PMP и он это сделает, скорее всего, это наш роутер. Первый этап: нахождение роутера 1. Взять из конфига, если есть 2. Разослать SSDP запрос, посмотреть, кто откликнется Без рутовых прав мы не можем: сами пользоваться ICMP, слушать сетевые интерфейсы / переводить их в промискуитетный режим. Не зная на какой мы системе, мы не можем вызывать команды типа ipconfig/ifconfig/ip addr (хотя можем попытаться перебрать их все) (Посмотреть, как сделать в libpcp --- оно каким-то образом пытается найти default gateway сначала). ## 2023-02-23 TODO: http-cache-protocol Сделать http worker, который будет поддерживать команды ``` GET /hash/read GET /hash/cat ``` для чтения блока и стриминга блока соответственно. Сделать протокол согласования HTTP CACHE, наподобие ``` data HttpCache = HttpCacheRequestRead... | HttpCacheRequestCat ... | HttpCacheAnnounceRead ... | HttpCacheAnnounceCat ... ``` Смысл в том, что публично доступная нода может просто анонсировать свой HTTP Cache, и все могут качать с него. Файлы будут отдаваться системным вызовом sendfile, снимая всякую нагрузку с нас. В дальнейшем можно сделать тоже самое для QUIC. То есть, сигнализация будет ходить по нашему UDP, а вот проблематичные жирные процессы будем выносить вовне. При таком подходе, кстати, можно взять не хаскельную реализацию QUIC, а любую устраивающую. Нам по факту надо поддержать только скачивание, остальные команды вполне могут ходить по UDP. Напомним, что пытаться контролировать чтение каким-либо образом, кроме криптографической защиты - бессмысленно. Можно даже не утруждаться аутентификацией. ## 2023-02-22 TODO: prefer-local-peers Надо запоминать факт, что Peer приехал через локальный AnnouncePeer. В дальнейшем, если приезжает локальный пир с одинаковым nonce - надо брать локального. А если есть локальный и приезжает глобальный --- то надо оставлять локального. TODO: known-peer-file Сделать опцию known-peer-file при старте hbs2-peer читает все такие файлы и добавляет все known-peer из них к общим known-peer TODO: known-peer-options-for-config При старте hbs2-peer читает все known-peer из конфига и пингует их TODO: drop-peer-loop-when-peer-removed FIXME: unknown-busyloop FIXME: fix-removing-inactive-peers Сейчас как-то слишком криво удаляет их. Не надо сначала увеличивать счётчик, потом ловить пинги. ## 2023-02-19 FIXME: peer-does-not-answer-to-pings Вероятно, или проблема формирования обратного адреса (sockaddr) Или проблема с хэшированием/доставанием из кэша (вряд ли). Нужно печатать sockaddr перед посылкой сообщения и отлаживать. Второй вариант -- какой-то поток падает и исключение глотается в async-ах. ## 2023-02-17 TODO: reference-basic-implementation see pep-04.txt TODO: extract-hbs2-core ``` $$$ (set workflow backlog) ``` Оставить в hbs2-core только реализацию Messaging и Peer. Сам протокол вынести в отдельный пакет, так, что бы на hbs2-core можно было реализовывать самые различные протоколы. TODO: hbs2-print-acb TODO: hbs2-create-acb 1. From a text script 2. ACB is a monoid: ACB + ACB = ACB 3. Default ACB has root ## 2023-02-16 TODO: cat-metadata-command Добавить команду, которая печатает метаданные ann. merke tree, если они есть и/или тип объекта (merkle, ann-merkle, blob) Если дерево зашифровано -- выводит в том числе хэш ключа TODO: check-group-encrypt-case-works 1. создать group key 2. положить его в store 3. сохранить зашифрованный им файл 4. достать сохранённый group key 5. расшифровать им файл FIXME: group-key-is-public ``` cat ./group1.key # hbs2 groupkey file # keep it private ``` group key is actually public. it contains encrypted records FIXME: group-key-new-brokes-on-empty-line ``` cat pub 3YpCdSGw7BdTVTpaWUMxF1DbWcTwAsH6ai3wRXfvCYx6 ./bin/hbs2 groupkey-new ./pub bad pubkeys file ``` ## 2023-02-15 FIXME: create-default-config FIXME: wrong-default-config-path TODO: make-key-optional-parameter -k should be an optional parameter cause it comes from config now TODO: check-if-block-announce-sufficient Нужно проверить, достаточно ли BlockAnnounce + BlockChunks для скачивания блоков в обе стороны. Кейс, вызывающий вопросы: ``` [A] (NAT) [B] | * block-announce | +------*--------------------->+ | * | | * get-block-size | +<-----*----------------------+ | * | | * | | * block-size | +------*--------------------->+ | * | | * get-block-chunks | +<-----*----------------------+ | * | | * | ``` Во вторых, если блок A предлагает какой-то блок, то высока вероятность того, что у других участников его еще нет --- и если спрашивать о нём всех и ждать ответа, это может привести к тому, что блок будет качаться очень медленно. Нужно как-то или использовать веса (пиров для данного блока), или же спрашивать параллельно всех о размере блока и на следующей итерации качать блок у того, кто сообщил размер. Кстати говоря, нас тут могут обманывать, возможно, нужно в BlockSize добавить какой-то пруф, что у пира есть такой блок. ## 2023-02-14 ## 2023-02-12 FIXME: busyloop-postponed Когда остаются одни posponed блоки в очереди, которых ни у кого нет --- возникает busyloop и флуд GetBlockSize Кажется, надо в ключ HasTimeLimits добавить хэш пингуемого блока. TODO: introduce-peer-config 1. На одном хосте может быть несколько пиров. 2. Конфиг пира --- это каталог. 3. Сторейдж --- это стейт, следовательно, конфиг должен быть отдельно 4. Конфиг является в основном линейным, т.е изменение может происходить дописыванием настроек в конец TODO: introduce-peer-black-list TODO: peer-accept-block-announce-feature Смотреть, если пир в чёрном списке --- от отвергать от него BlockAnnounce и handshake. ## 2023-02-09 TODO: MerkleWrap-to-MerkleAnn-or-AnnMerke ($context (commit d81038140c795e1cf30cfa05e95630ca1e639427) (file hbs2-core/lib/HBS2/Data/Detect.hs 143) ) Заменить MerkleWrap на AnnotatedMerkle или MerkleAnn Смысл --- Merkle дерево с аннотацией. AnnRef, получается, более не нужны. Ссылка всегда ссылается на дерево, наверное, всегда аннотированное. У ссылки, в свою очередь, есть ссылка на AccessControlBlock. TODO: encryption-keys-into-credentials-file дизайн данных: ``` data Credentials = Credentials SignKey [(KeyId, KeyMetadata, KeyPair)] ``` он же "keyring", это буквально связка ключей. операции: ``` hbs2 keyring list ``` показывает публичные ключи в связке и их типы и прочее ``` hbs2 keyring add-new [-n key-id] ``` добавляет ключ ``` hbs2 keyring del -n key-id ``` удаляет ключ Этот же формат ключ можно использовать и самому пиру, т.к. ему тоже нужны будут потом ключи шифрования. Единственное, пир должен знать какой ключ из связки использовать, но это может быть либо по умолчанию первый ключ, либо передавать как-то в конфиге или же аргументах. ## 2023-02-07 FIXME: suckless-conf Настало время выдохнуть и сделать fixme, потому, что их становится слишком много. FIXME: Более мудрый алгоритм для pokePostponed Сейчас оно слишком часто просыпается и забрасывает блоки в общую очередь, что приводит к busyloop в blockDownloadLoop. Введение HasTimeLimits улучшило ситуацию, но не сильно. Алгоритм должен быть что-то наподобие: Посмотрели, сколько раз блок процессировался подряд. Если больше, чем X - то (что?) в общем, выкинули обратно в postponed. С другой стороны, может GetBlockSize можно рассылать из pokePostponed, и просыпаться, если пришёл размер нашего блока ## 2023-02-06 Ну а так, базовый PEX заработал TODO: Добавлять пиров в KnownPeers только после того, как они пинганулись. Т.е пинговать пиров, если их еще нет. Не добавлять в KnownPeers до того, как ответили на пинг. TODO: Научиться убирать дубликаты пиров. Их можно распознать по PeerNonce, но непонятно, какой из пиров оставлять. Иначе это будет реально большая проблема при скачивании. TODO: Убедиться, что subscribe на перманентное событие НИКОГДА не вызывается в рекурсии. Проверить ВСЕ subscribe. Возможно, вставить проверки в рантайм. Возможно, ограничить число таких событий и ругаться в рантайме. FIXME: При вычислении burst надо каким-то образом находить плато и не лезть выше него. FIXME: Задержку в очередь пиров при рассылке GetBlockSize, что бы не спамить пиров, пока запрос не уехал в отстой. Надо для каждого пира поставить задержку в 0.5 defBlockInfoTimeout или наоборот, в 1 defBlockInfoTimeout. #medium #asap FIXME: добавить peer-nonce в peer-data что бы можно было определять себя при пинге и вычеркивать из known-peers, что бы пакеты по кругу не гонять. #easy ## 2023-02-05 ### fixme Багтрекеры не нужны. Нужно сделать утилиту fixme, которая будет вести список FIXME/TODO из файлов. Формат FIXME/TODO достаточно расслабленный, но с определёнными условностями (TBD). Каждая такая запись привязывается к файлу/строчке/гитовому коммиту. Оттуда и берёт автора, и как-то трекает историю. Изменения workflow делаются отдельными записями, можно еще с криптоподписью (взять тот же самый credentials). Аттачменты и прочее --- добавлять хэш-ссылками на 1. объект hbs2/offgrid 2. git blob Тогда, если по этому гитовому хэшу объект где-то находится (в т.ч. вообще в любом репозитории, у нас же может быть глобальный словарь sha1 <-> offgrid-hash) то - рисуем картинку или изображаем аттачмент. ### Про PEX Надо делать PEX. PEX очень простой: ``` data PEXEntry e = PEXAdd (PeerAddr e) | PEXDel (PeedAddr e) | PEX data PEX e = PEXRequest ??? | PEXResponse ??? [PEXEntry] ``` На самом деле, кто тут судьи? Кто может нам сказать - добавить пира или удалить. Только мы сами можем решать. Поэтому, PEX может быть редуцирован до: `````````````````````````````````````````````` data PEX e = PEXRequest ??? | PEXInfo [PeerAddr e] (Maybe ???) A B + -> PEXRequest -> + | | + <- PEXInfo xxx ??? <- + | | | | `````````````````````````````````````````````` Вопрос, сколько пиров за раз отдавать, как можно нас зафлудить битыми пакетами и т.д. Информацию о пирах лучше сделать вообще отдельным протоколом, что бы не загромождать этот. Тогда останется только ``` data PEX e = PEXRequest ??? | PEXAnswer [PeerAddr e] ``` Оценочные суждения, что пир такой-то --- редиска и т.п. можно оставить за кадром. Там нужны пруфы или сеть доверия, для сети доверия надо хранить статистику пиров (что, кстати, можно). То есть если пир, который у нас на хорошем счету, или его хороший пир говорят нам, что какой-то другой пир --- плохой, то этому можно верить. Вопрос, база локальная или база глобальная. Вообще, это целая большая история и пока не до неё. ## 2023-02-03 FIXME: Перестаёт качать ближе к концу файла. После повторного анонса --- докачивает. FIXME: Надо поднимать burst в процессе скачивания блоков FIXME: Надо динамически повышать/понижать burst в процессе скачивания NOTE: Почему вообще получается потеря пакетов? Такого не должно быть. TODO: Нужно исследовать потерю чанков/блоков, и произвести сравнительные замеры при помощи iperf/netperf что бы понять, теряются ли вообще пакеты или нет. ## 2023-02-01 Вести баги это слишком формально и накладно, даже в упрощенном виде. Можно вести их в виде девлога. FIXME: Обработка ошибок в асинхронном приложении. Async-и жрут исключения, даже, когда удаётся их перехватить и пробросить дальше. Например, если не удалось забиндиться на адрес, исключение стреляет, но код ошибки при выходе всё еще 0. ## 2023-04-03 PR: implement-http-block-download-worker branch: iv/http-block-download-worker-5 commit: c1b32d9b7d4ad46f1924bf340374d64c29cefb67 Скачивание блока по http. Решение 7gN8M32Ugm (http-block-download-worker) ## 2023-05-15 PR: tcp-pex branch: iv/tcp-pex_3 commit: f1de7c58d5dc36dec5c318a3297733791de9a3d8 ## 2023-06-15 PR: bus-crypt branch: iv/bus-crypt Шифрование протокола общения нод. Обмен асимметричными публичными ключами выполняется на стадии хэндшейка в ping/pong. Для шифрования данных создаётся симметричный ключ по diffie-hellman.