mirror of https://github.com/voidlizard/hbs2
wip
This commit is contained in:
parent
5b052e8a56
commit
32a7ecfd70
|
@ -0,0 +1,200 @@
|
|||
NOTE: on-refchans-1
|
||||
Написал, что фиксация владельцем истории не меняется, и это инвариант.
|
||||
Смешно получилось.
|
||||
|
||||
Коротко:
|
||||
|
||||
1) Нам хочется изобразить что-то, желательно CRDT, без
|
||||
полноценного онлайн-консенсуса, но при этом с возможностью
|
||||
управлять правами. В идеале и чтения и записи в журнал для
|
||||
многих авторов.
|
||||
|
||||
2) (опущены промежуточные выкладки, плоды, между прочим,
|
||||
дней страданий и выброшенного на помойку кода)
|
||||
CRDT такой пишется, но даёт возможность зловредным авторам и
|
||||
корумпированным ими узлам отравлять историю, поскольку даже
|
||||
если автора удалили из ACL, он может на своём узле не принять
|
||||
это обновление и несмотря на то, что его обновления не будут
|
||||
принимать на добросовестных узлах --- если кто-то придёт
|
||||
за журналом на его узел, он сможет невозбранно писать
|
||||
"исторические" записи, ссылаясь на любой ACL/HEAD, где он
|
||||
еще был
|
||||
|
||||
3) CRDT в целом не стоек к византийскому поведению, атаки
|
||||
на него придумываются легко и быстро
|
||||
|
||||
4) Не хочется заставлять владельца канала делать какие-то
|
||||
действия оперативно, по замыслу -- владелец это просто ключ,
|
||||
который хранится в сейфе, и на свет выходит, только когда
|
||||
нужно поменять какую-то существенную метаинформацию, например,
|
||||
инициирвать форк ну или ACL поменять
|
||||
|
||||
5) В общем, нам надо придумать какие-то однозначные правила,
|
||||
которые бы позволили бы принимать транзакции только относительно
|
||||
валидного "в сейчас" ACL/HEAD и дать какие-то однозначные правила
|
||||
интерпретации журнала, которые бы могли при прочтении лога
|
||||
дать возможность установить, что записи были сделаны в соответствии
|
||||
с актуальными в моменте ACL.
|
||||
|
||||
Решение:
|
||||
|
||||
1. Для каждой транзакции требовать нескольких подтверждений от разных
|
||||
пиров (нод).
|
||||
|
||||
1. Писать транзакции в журнал, если есть несколько
|
||||
подтверждений.
|
||||
|
||||
3. ACL устанавливает не только набор авторов, но и набор пиров,
|
||||
которые могут подтверждать транзакции. Эти пиры подписывают
|
||||
транзы и постят PROPOSE/ACCEPT. Остальные пиры могут только
|
||||
транслировать их через Gossip. Неприятное следствие:
|
||||
журнал будут писать только авторизованные пиры, значит,
|
||||
количество его экземпляров будет ограниченно ими. Но может,
|
||||
это и к лучшему.
|
||||
|
||||
4. Каждая транзакция подписывается и ключом автора, и ключом
|
||||
пира и содержит ссылку на актуальный ACL/HEAD, подписанный
|
||||
владельцем канала/журнала/ссылки
|
||||
|
||||
5. При чтении журнала учитывать только те транзакции,
|
||||
которые удовлетворяют правилам, установленным в HEAD (число
|
||||
подтверждений)
|
||||
|
||||
6. Остаётся проблема, что делать, если приехали записи задним
|
||||
числом --- если их отвергать, то журналы могут не сойтись,
|
||||
а если принимать --- то остаётся проблема с отравлением
|
||||
истории.
|
||||
|
||||
Единственное, что тут вижу --- всем нодам принимать
|
||||
"исторические" записи в течение какого-то периода после
|
||||
обновления HEAD и не принимать после. Ну типа, за минуту-то
|
||||
всяко все транзы разойдутся, а позже не принимаем.
|
||||
|
||||
|
||||
Как можно видеть --- этот подход смесь CRDT (однозначные
|
||||
правила интерпретации журнала) и "онлайн" консенсуса,
|
||||
тут примерно половина его. "Полусенсус" -- по сути,
|
||||
есть PROPOSE и VOTE (у нас: ACCEPT), остальные выводы
|
||||
относительно того, что делать с этими транзакциями
|
||||
можно делать, или интерпретируя журнал, или вводя
|
||||
дополнительные транзакции, которые уже обрабатываются
|
||||
сторонними приложениями. Т.е тут опущены фазы
|
||||
VALIDATE/PRECOMMIT/COMMIT. Предполагается, что "авторы"
|
||||
постят уже валидные транзакции, а договориться, какая
|
||||
транзакция являестся валидной, они должны отдельно,
|
||||
если им надо, при помощи "эфемерных" транзакций.
|
||||
|
||||
|
||||
|
||||
|
||||
NOTE: refchan-log-syncronization-1
|
||||
что мы тут делаем.
|
||||
1. Получили merkle лога
|
||||
2. Надо читать лог, если мы его еще не обработали.
|
||||
Каждую транзу из него валидировать,
|
||||
и если мы его еще не обработали --
|
||||
писать вон в refChanWriteQ
|
||||
Теперь вот прикол: авторы траз будут верифицированы относительно
|
||||
"сейчас", а не "тогда". То есть, если к нам едут старые записи,
|
||||
а мы не знаем, в каком они контексте -- то они будут отвергнуты
|
||||
относительно "сейчас". То есть еще раз: лог едет, допустим,
|
||||
старый и некоторым авторам в него писать было можно.
|
||||
А сейчас --- нельзя. Такие транзакции не пройдут валидацию.
|
||||
Верно и обратное: если добавлены пермишены для каких-то авторов,
|
||||
но мы эту информацию еще не получили --- то такие транзакции
|
||||
будут отвергнуты.
|
||||
Какое видится решение:
|
||||
1. Любую метаинформацию обрабатывать отдельно и сразу.
|
||||
2. Транзакции откладывать, если они валидные, но не прошли
|
||||
проверку.
|
||||
Источник метаинформации всегда один --- это владелец ссылки.
|
||||
"Рано или поздно" метаинформация у всех обновится, и мы перенакатим
|
||||
отложенные транзакции.
|
||||
|
||||
Второй вариант. Поскольку лог транзакций приезжает всегда весь, пусть и по
|
||||
частям.
|
||||
|
||||
Мы можем обрабатывать транзакции из него в контексте тех ACL, что есть в нём
|
||||
же, а не глобальных. Соответственно, сначала принимаем только те
|
||||
транзакции, что соответствуют логу.
|
||||
|
||||
принимаем все транзакции на обновление метаинформации. Объединяем этот лог и
|
||||
свой.
|
||||
|
||||
|
||||
Какую мы задачу решаем:
|
||||
|
||||
Как принимать или отвергать транзакции в условиях частичной несинхронности
|
||||
состояния?
|
||||
|
||||
Метаинформация (ACL) не имеет контекста сама по себе.
|
||||
|
||||
Но всегда имеет контекст в плане принятого журнала -- т.е та
|
||||
информация, что там определена, та и влияет на приём транзакций
|
||||
из этого журнала.
|
||||
|
||||
Таким образом, у нас есть следующие варианты обработки транзакций.
|
||||
|
||||
Вариант 1
|
||||
|
||||
1. Принять журнал
|
||||
|
||||
2. Обновить сначала метаинформацию из него
|
||||
|
||||
3. С обновленной метаинформацией принимать транзакции из него
|
||||
|
||||
4. Непринятые транзакции откладывать и пытаться принять их потом
|
||||
|
||||
Замечание: если узел прислал журнал, в котором есть транзакции,
|
||||
которые не соответствуют метаинформации (acl) --- это вызывает
|
||||
вопросы к этому узлу. Такие транзации нужно отвергать.
|
||||
|
||||
Таким образом, мы:
|
||||
|
||||
В контексте одного присланного лога:
|
||||
|
||||
- Извлекаем метаинформацию
|
||||
- Обрабатываем транзакции с **этой** метаинформацией
|
||||
- Добавляем только транзации, которые прошли верификацию
|
||||
- Помечаем лог обработанным
|
||||
- Конец.
|
||||
|
||||
Итого, как же нам обработать присланный журнал?
|
||||
|
||||
1. Скачали журнал
|
||||
|
||||
2. Поставили в очередь на обработку, если еще не обработан
|
||||
|
||||
3. В процессе обработки:
|
||||
|
||||
3.1 Достаём метаинформацию и обновляем стейт
|
||||
|
||||
3.2 С сохранённой метаинформацией (из стейта) проигрываем
|
||||
журнал транзакций.
|
||||
|
||||
Что тут плохо:
|
||||
|
||||
Стейт глобальный. Если метаинформацию держать глобально,
|
||||
то она не будет соответствовать тому контексту, в котором существует присланный лог.
|
||||
|
||||
Нужно каждый лог обрабатывать отдельно в его контексте.
|
||||
|
||||
В чём минусы: он может быть огромный и нас можно легко
|
||||
зафлудить.
|
||||
|
||||
Как решать?
|
||||
|
||||
1. Не обрабатывать то состояние, которое у нас уже было.
|
||||
Мы должны вести историю.
|
||||
|
||||
2. Не запрашивать (fetch) лог просто так.
|
||||
|
||||
Сейчас инструкция poll ведёт именно к периодическому
|
||||
запросу. В принципе, если не обрабатывать те логи,
|
||||
что мы уже обработали, это должно быть достаточно
|
||||
безвредно, если не очень часто.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -45,8 +45,8 @@ import Data.Text qualified as Text
|
|||
import Data.Text.Encoding qualified as TE
|
||||
import Data.Time.Clock (NominalDiffTime)
|
||||
import Data.Heap qualified as Heap
|
||||
import Data.Heap (Heap,Entry(..))
|
||||
import Data.Time.Clock
|
||||
import Data.Heap (Entry(..))
|
||||
-- import Data.Time.Clock
|
||||
|
||||
data PeerInfo e =
|
||||
PeerInfo
|
||||
|
|
|
@ -68,6 +68,7 @@ common common-deps
|
|||
, unliftio
|
||||
, unix
|
||||
, heaps
|
||||
, psqueues
|
||||
|
||||
common shared-properties
|
||||
ghc-options:
|
||||
|
|
Loading…
Reference in New Issue