Жеребьёвка: кто создаёт следующий блок
В Proof of Participation никто не соревнуется за право создать блок. Для каждой новой высоты случайная жеребьёвка по реестру узлов по порядку называет производителей: первый жребий называет производителя раунда 1, второй — производителя раунда 2 и так далее. Каждый узел проводит одну и ту же жеребьёвку на одних и тех же данных и получает тот же список, поэтому каждый узел знает, кто может создать следующий блок, и отклоняет блок от кого-либо другого.
Лотерея, которую может повторить каждый
Честной жеребьёвке нужна случайность, которую никто не контролирует и которую каждый может воспроизвести. ZooBC берёт её из предыдущего блока. Каждый блок несёт 64-байтовый сид — значение, которое его производитель не может выбрать (см. Сид блока (VRF)). Сид запускает генератор псевдослучайных чисел, и каждое число, выданное генератором, выбирает одну запись из списка узлов, которые могут участвовать в жеребьёвке.
Сид блока появляется только вместе с самим блоком, поэтому никто не знает порядок для следующего блока заранее: обычно он известен лишь на один блок вперёд. (Злоумышленник, владеющий многими местами, иногда может заглянуть дальше; см. Сид блока (VRF).) А поскольку у каждого узла один и тот же предыдущий блок и один и тот же реестр, каждый узел вычисляет один и тот же список. Здесь нет ни головоломки, которую нужно решить, ни публикуемого расписания, ни координатора.
Список, из которого тянут жребий
Жеребьёвка выбирает из набора жеребьёвки:
- это активный реестр на момент предыдущего блока, то есть допущенные (зарегистрированные) узлы; узлы в очереди в него не входят;
- он упорядочен по идентификатору узла, от меньшего к большему (идентификатор узла берётся из первых 8 байт его ключа узла);
- из него исключён каждый узел, на который действует приостановка (см. Пропущенные ходы, приостановка и исключение). Если после этого не осталось бы никого, вместо него используется весь активный набор.
Если приостановлены все активные узлы, в набор добавляется лучший узел из очереди, который поддерживал свою явку, как кандидат на возобновление (см. Очередь), чтобы цепочка всегда могла перезапуститься; блок от такого узла сразу же его допускает.
Блоки проверяются строго по реестру на момент предыдущего блока, без обращения к какой-либо другой высоте. Блок от узла, который не был выбран жеребьёвкой для своего раунда, отклоняется каждым узлом.
Генератор
Точный рецепт, которому каждая реализация должна следовать бит в бит:
h = SHA3-256("zbc-blocksmith" ‖ seed of the previous block)
v = bytes 24 to 31 of h, read as a big-endian 64-bit number
Splitmix64(v) seeds a xoroshiro128+ generator
each draw: r = the next non-negative 63-bit number
the draw names entry (r mod n) of the selectable set, n = its size
Жребий 1 называет производителя раунда 1, жребий 2 — производителя раунда 2 и так далее (см. Раунды, время и окна). Жребии независимы, поэтому один и тот же узел может быть назван в одном списке больше одного раза.
Метка zbc-blocksmith отделяет эту жеребьёвку от других случайных выборов, которые делаются по сидам блоков; у каждого из них своя метка: zbc-coinbase для лотереи coinbase, zbc-receipt и zbc-receipt-datum для квитанций, zbc-topology-v2 для топологии пиров и zbc-apps для приложений.
У каждого места одинаковый шанс
Каждый жребий выбирает любую запись набора жеребьёвки с одинаковой вероятностью. Больше ничего не учитывается: ни оборудование узла, ни баланс его владельца, ни его стейк, ни его оценка участия. Оператор, которому принадлежат 3 из 30 активных мест, создаёт примерно один блок из десяти.
В этом первая цель дизайна Proof of Participation: равная для всех власть над производством блоков. Единственный путь к большей власти — больше мест, а места приходят только через очередь, по одному допуску за раз, в темпе, который задаёт протокол (см. Темп допуска). Оценка участия не влияет на жеребьёвку намеренно: узел с высокой оценкой зарабатывает больше, но не создаёт больше блоков, не выбирает больше сидов и не получает больше возможностей не включить транзакции в блок.
Два уточнения
- Предыдущий производитель. Узел, создавший предыдущий блок, остаётся в наборе жеребьёвки, но его жребии засчитываются не раньше раунда 10, поэтому следующий блок он создаёт только как поздний запасной вариант. См. Приоритетные раунды, пустые блоки и предыдущий производитель.
- Поздние раунды. Производители начиная с раунда 11 могут создавать только блоки без транзакций. См. также приоритетные раунды, пустые блоки и предыдущий производитель.