Валидатор оракла Отметки времени
Сторонним пользователям Solana иногда необходимо знать реальное время создания блока, как правило, для выполнения требований соответствия для внешних аудиторов или правоохранительных органов. В этом предложении описывается оракул временных меток валидатора, который позволит кластеру Solana удовлетворить эту потребность.
Общая схема предлагаемой реализации выглядит следующим образом:
-
Через регулярные промежутки времени каждый валидатор записывает наблюдаемое время для известного слота в цепочке (через временную метку, добавленную к голосованию слота).
-
Клиент может запросить время блока для корневого блока, используя RPC-метод getBlockTime. Когда клиент запрашивает метку времени для блока N:
-
Валидатор определяет отметку времени «кластера» для последнего слота с отметкой времени перед блоком N, наблюдая за всеми инструкциями Голосования с отметкой времени, записанными в реестре, которые ссылаются на этот слот, и определяя средневзвешенную отметку времени по доле.
-
Эта недавняя средняя временная метка затем используется для вычисления временной метки блока N с использованием установленной длительности слота кластера.
-
Требования:
- Любой валидатор, воспроизводящий реестр в будущем, должен указывать одинаковое время для каждого блока с момента его создания.
- Расчетное время блока не должно смещаться более чем на час или около того, прежде чем оно будет преобразовано в реальные данные (оракула).
- Время блока не контролируется одним централизованным оракулом, а в идеале основано на функции, которая использует входные данные от всех валидаторов.
- Каждый валидатор должен поддерживать оракул временной метки
Та же реализация может предоставить оценку временной метки для еще не укоренившегося блока. Однако, поскольку самый последний слот с временной меткой может быть еще не внедрен, эта временная метка будет нестабильной (потенциально несоответствующей требованию 1). Первоначальная реализация будет нацелена на корневые блоки, но если есть вариант использования временной метки последнего блока, в будущем будет несложно добавить API RPC.
Время записи
Через регулярные промежутки времени, когда он голосует в определенном слоте, каждый валидатор записывает наблюдаемое время, включая временную метку в свои инструкции по голосованию. Соответствующий слот для метки времени является самым новым слотом в векторе голосования (Vote::slots.iter().max()
). Он подписывается парой ключей идентификации валидатора как обычное голосование. Чтобы включить эту отчетность, структуру Vote необходимо расширить, включив в нее поле временной метки timestamp: Option<UnixTimestamp>
, для которого будет установлено значение None
в большинстве голосов.
Начиная с https://github.com/solana-labs/solana/pull/10630, валидаторы отправляют метку времени для каждого голосования. Это позволяет реализовать службу кэширования времени блока, которая позволяет узлам вычислять предполагаемую временную метку сразу после того, как блок укоренен, и кэшировать это значение в Blockstore. Это обеспечивает постоянные данные и быстрые запросы, но при этом удовлетворяет требованию 1) выше.
Аккаунты для голосования
Учетная запись для голосования валидатора будет содержать самую последнюю временную метку слота в VoteState.
Программа голосования
Программу голосования в цепочке необходимо расширить для обработки метки времени, отправленной с инструкцией по голосованию от валидаторов. В дополнение к своей текущей функциональности process_vote (включая загрузку правильной учетной записи Vote и проверку того, что лицо, подписывающее транзакцию, является ожидаемым валидатором), этому процессу необходимо сравнить метку времени и соответствующий слот с текущими сохраненными значениями, чтобы убедиться, что они оба монотонно увеличиваются. и сохраните новый слот и метку времени в учетной записи.
Вычисление средневзвешенной временной метки
Чтобы рассчитать предполагаемую отметку времени для конкретного блока, валидатору сначала необходимо определить слот с самой последней отметкой времени:
let timestamp_slot = floor(current_slot / timestamp_interval);
Затем валидатору необходимо собрать все транзакции Vote WithTimestamp из реестра, которые ссылаются на этот слот, используя Blockstore::get_slot_entries()
. Поскольку для достижения этих транзакций и их обработки лидером могло потребоваться некоторое время, валидатору необходимо просканировать несколько завершенных блоков после timestamp_slot, чтобы получить разумный набор временных меток. Необходимо настроить точное количество слотов: большее количество слотов позволит увеличить участие кластера и увеличить количество точек данных с отметками времени; меньшее количество слотов ускорит фильтрацию временных меток.
Из этой коллекции транзакций валидатор вычисляет средневзвешенную временную метку, ссылаясь на доли эпохи из staking_utils::staked_nodes_at_epoch()
.
Любой валидатор, воспроизводящий реестр, должен получить одну и ту же средневзвешенную временную метку, обрабатывая транзакции временной метки из одного и того же количества слотов.
Расчет предполагаемого времени для определенного блока
После того как рассчитана средняя временная метка для известного слота, вычислить предполагаемую временную метку для последующего блока N несложно:
let block_n_timestamp = mean_timestamp + (block_n_slot_offset * slot_duration);
где block_n_slot_offset
— это разница между слотом блока N и timestamp_slot
, а slot_duration
получается из кластера slots_per_year
, хранящегося в каждом банке.