12 KiB
PEP-03: update-reference
Задача: необходимо обеспечить контроль прав доступа при постинге блоков (куда? TBD).
Пока существует только BlockAnnounce, который просто декларирует, что пир X имеет блок Y.
Решение, скачивать его или нет принимает узел на основании каких-то своих настроек.
Нужно ввести какую-то сущность (reference? topic?) которая даёт возможность постить блоки "куда-то", на что бы принимающая сторона имела возможность решать - принимать эти блоки или нет, и если принимать --- то скачивать данные блоки у узла.
[A] [B]
| (suggest-ref-update ref (upd sign block) |
+---------------------------------------------->+
| | (check sign)
| | (check perm ACB)
| (get-blok-size block) |
+<----------------------------------------------+ (if ok)
| |
| (get-block-chunks) |
+<----------------------------------------------+
| |
| (chunk X ...) |
+---------------------------------------------->+
| |
| |
Открытые пока что вопросы:
-
Предлагать новую голову топика или предлагать блоки в топик?
-
Если предлагать новую голову, сойдется ли вообще когда-либо топик?
-
Если мы считаем, что
topic ::= set blob
то это даёт нам возможность запрашивать разницу между тем, что есть у нас, и тем, что есть у узла.
Таким образом, мы можем считать, что "topic" (reference) это merkle tree включённых в него блоков + ACB.
Поскольку алгоритм упорядочивания блоков может отличаться в зависимости от применения, а где-то и не требоваться вовсе, то сами блоки могут упорядочиваются исключительно лексикографически (TBD?!) по их хэшам. Что приводит нас к тому, что merkle tree данных и merkle tree топика это разные вещи (!!!). Так как как данных обязателен порядок узлов дерева.
Отсюда у нас два выхода:
-
Ввести вариант merkle tree где явно задан порядок блоков (файл!)
-
Ввести вариант merkle tree, где порядок не задан и определяется только самими хэшами. Открытый вопрос --- сортировать тексты хэшей или их бинарное представление.
Мы можем:
-
Получить difference (merkle опять?) между нашим содержимым и содержимым пира
-
Скачать блоки из difference
-
Упорядочить топик
-
Получить difference
-
Если сошлось, то успокоиться
-
Если не сошлось, то вернуться на шаг 1.
Если не делать какого-то рода барьеров (аналог высоты в БЧ), то при большом количестве узлов, которые пишут данные, данный алгоритм, КАЖЕТСЯ, не сходится (доказать или очевидно? При отсутствии какого-то рода барьера, обязательного для всех, в любой момент времени может найтись узел, который добавит узлы в топик, таким образом, его состояние и состояние всех других узлов будет различным. Если мы упорядочим состояние между N узлами и этим узлом, то всегда может найтись другой узел, который добавит "пост" в "топик" и состояние между ним и теми N узлами опять окажется различным.
Каким образом можно ввести барьеры?
- Ограничить число узлов, которые могут принимать решение о включении блока в "топик".
Если их ограничить до одного, а этот один будет определяться тем, что он смог посчитать какое-то значение, удовлетворяющее условиям --- получится PoW.
Если их ограничить N узлами, которые должны подписать транзакцию своими ключами, например, k/N ключей --- то получится что-то наподобие PoA.
Если их ограничить N узлами, которые должны согласовать контент и в реальном времени принять решение о включении --- то получится что-то наподобие PoS/PBFT.
Нам нужен такой способ, который не требует обязательного ответа от всех известных уполномоченных участников. Подходит: PoW, PoA (с вариациями). PoW требует каких-то издержек на вычисления, что может при малом числе участников приводить к каким-то ненужным задержкам при добавлении блоков.
В данном применении (последовательность постов от ограниченного числа участников) у нас нет необходимости решать задачу отсутствия double spend, т.к. нет объекта для double spend. Решаемая задача --- включать блок в set, или нет.
- Какого-то рода временнЫе барьеры?
Например, некие узлы уполномочены выдавать некие токены, зависящие, например, от времени, или просто гарантированно уникальные и для которых определена последовательность. Тогда нам нужно просто гарантировать, что в каждый момент времени будет принят (по некоему алгориму) только один такой токен, с неким временем жизни (пока не выдан следующий токен).
Тогда каждый узел для каждого топика ведёт список известных ему токенов.
Когда узел предлагает блок --- он запрашивает у авторизованных узлов этот токен либо же генерирует его сам, если он сам авторизованный узел и сообщает его остальным.
При постинге блока постящий узел --- узнаёт токен и включает его в предложение блока. Принимающий узел --- узнаёт токен и если предлагаемый токен устарел --- то блок отвергается, если не устарел -- то принимается.
Таким образом, мы принуждаем узлы к коммуникациям и синхронизации, избегаем ситуации, когда какой-то узел постит блоки сам себе, а потом своё состояние выкидывает всем, принуждая всех участников пересчитывать состояние.
Таким образом, при постинге блока мы:
- Опрашиваем всех известных нам узлов
- Получаем с каждого токен
- Выбираем токен, который есть у большинства участников
- Публикуем блок (рассылаем известным узлам)
- Каждый узел, получивший блок --- принимает его, если верны доказательства валидности блока (ACB + токен актуален)
- Если (и обязательно) в токен ввести что-то хэш от известного состояния топика --- то мы обязуем постящую сторону выяснить это состояние, то есть, как минимум, скачать этот топик или узнать его состояние. То есть, синхронизироваться.
Еще раз: мы не решаем задачу BFT. Может быть, она решается таким путём, может быть, нет, неизвестно. Наша задача --- принудить узлы к синхронизации перед публикацией своего контента и ввести некий порядок для блоков.
Можно ли включать в токен время, как естественное, известное всем, монотонно возрастающее значение? Никакого Proof-Of-Time не существует.
Наша задача --- выбирать актуальные, добросовестные узлы и сотрудничать с ними.
Вопрос, почему узел должен быть актуальным и добросовестным мы выведем за рамки данного документа.
Итого, примерный алгоритм, кажется, выглядит так:
- Посчитать x = f1(известное-нам-состояние-топика)
- Узнать текущий токен t = T(топик) у известных нам узлов
- Посчитать значение y = f2(t,x)
- Опубликовать (разослать всем известным узлам? или тем, с которыми разговаривали? или всем, но в приоритете тем, с кем разговаривали?) контент, включающий y.
- Принимающая сторона рассматривает y, если он актуален (TBD), то включает блок. Если нет -- то отвергает.
Более простой вариант:
-
Постящий узел включает число, определяемое предыдущим известным ему состоянием
-
Принимающий узел смотрит: было ли такое состояние вообще когда-либо ранее, и если было --- то как давно (Сколько голов тому назад). Если было слишком давно (TBD), то блок не выключается, принуждая постящий блок синхронизироватьсяи перересчитать число.
Если к этому варианту добавить nonce + "красивые хэши" мы получим защиту от того, что блоки постятся слишком часто и состояние топика не сходится у большинства.