Перейти к содержанию

Проверяемая случайность в Web3: модель задания

От проверки файла к назначению задания

До этого библиотека получала сведения о доступности выпуска и сохраняла результат проверки. Теперь добавим другую задачу: слушатель курса 17 получает один из четырёх вариантов упражнения. Выбирать вариант по последней цифре адреса удобно, но пользователь может перебрать адреса. Значение времени блока тоже не является надёжным источником случайности. Нужен механизм, который позволяет проверить происхождение случайного результата, а правила приложения должны не позволять заменить неудобный результат удобным.

Сначала определим, нужен ли здесь блокчейн. Для обычного учебного сайта серверное назначение зачастую достаточно. Проверяемая случайность имеет смысл, когда участникам важно независимо убедиться, что организатор не выбирал варианты вручную. Она добавляет задержку, плату и зависимости. В этой главе рассматриваем такой отдельный режим библиотеки; базовый CourseCatalog от этого не получает новых методов.

Фиксируем то, что выбирается

Введём отдельный модуль AssignmentRegistry. Перед запросом он сохраняет курс 17, выпуск 2, участника, четыре упорядоченных варианта и версию правил. Условные названия вариантов — «Хеширование», «Манифест», «Зеркало», «Архив». После запроса список неизменяем. Иначе организатор мог бы сначала узнать индекс, затем поставить любимое упражнение в соответствующую позицию.

Связываем запись приложения assignmentId с requestId сервиса. Ожидающий запрос имеет собственное состояние, но ответ нельзя приписать последнему зарегистрированному слушателю. Если ответы запросов A и B пришли в обратном порядке, сопоставление по идентификаторам сохраняет назначение каждому участнику. Адрес координатора и параметры сети относятся к выбранному профилю интеграции, а не вычисляются из номера курса.

Для учебного разбора используем Chainlink VRF 2.5. Подтверждения запроса выбираются по сети и риску приложения. Один универсальный номер здесь не задаём. Рекомендации VRF описывают связь requestId, фиксацию входов и защиту обработки результата.

Разбираем индекс без выдуманного доказательства

Пусть сервис вернул случайное 256-битное слово, а количество вариантов равно четырём. Индекс вычисляется как остаток от деления слова на четыре. Для равномерного значения из диапазона 256 бит это деление не создаёт смещения: размер диапазона делится на четыре. При произвольном количестве вариантов вопрос распределения требует отдельного анализа, поэтому не переносим вывод на любую длину списка.

// Только арифметическая модель выбора, не генератор VRF.
const word = 11n;
const variants = ['hash', 'manifest', 'mirror', 'archive'];
const index = Number(word % 4n);
const selected = variants[index];

Ожидаемый индекс равен 3, а вариант — archive. Число 11 задано нами для разбора. Оно не получено от сервиса и ничего не доказывает о случайности. Замена на 12 даёт индекс 0 и hash. Этот изменённый пример помогает проверить границу списка, но не качество источника случайных данных.

Теперь изменим вход приложения: после запроса добавим пятый вариант. Остаток от деления того же слова изменится на 1. Поэтому сохранить только слово недостаточно. Назначение должно ссылаться на зафиксированный набор, иначе последующее изменение интерфейса незаметно изменяет результат уже состоявшейся процедуры.

Приём ответа должен быть коротким

В настоящей интеграции публичная точка приёма защищается предусмотренным механизмом координатора. Для subscription-маршрута документация рекомендует VRFConsumerBaseV2Plus. Нельзя заменить защищённый вход обычным публичным методом, принимающим произвольное слово от любого адреса.

После подтверждённого входа callback сохраняет слово и отмечает получение. Здесь избегаем тяжёлых внешних вызовов, выдачи токенов или загрузки ресурсов. Если обработчик откатится, сервис не обязан присылать тот же ответ повторно. Сложное завершение назначения переносим в отдельное действие, которое читает сохранённый результат. Правило обработки callback особенно важно при изменении функций библиотеки.

Это разделяет два состояния: «случайное значение получено» и «назначение завершено». Ошибка интерфейса после получения не требует нового случайного значения. Пользователь возвращается к тому же assignmentId, а сайт показывает сохранённое назначение. Проверка идентификатора исключает случайное применение слова из другого запроса.

Почему задержка не разрешает переброс

Для проверки доступности HTTP мы обсуждали новые попытки. Применять тот же подход к случайному назначению нельзя. Возможность отменить запрос или запросить новое значение для того же обязательства позволяет отбросить неудобный результат. Организатор мог бы объявлять техническую ошибку каждый раз, когда библиотеке достаётся нежелательный вариант.

Поэтому после фиксации заявки нет кнопки «выбрать ещё раз». Если ответ задерживается, показываем ожидание и разбираем состояние исходного запроса. Отдельная аварийная политика должна быть объявлена заранее и не превращаться в выбор между уже известными результатами. Возврат платы, если он предусмотрен правилами, не равен разрешению повторного розыгрыша того же обязательства.

Даже в учебной системе стоит различать отсутствие ответа и потерю экранного состояния. Повторная загрузка страницы не создаёт assignmentId заново. Клиент читает существующую запись, поэтому отключённый интернет пользователя не меняет правила распределения.

Есть и различие между выдачей задания и проверкой ответа. Случайный индекс не доказывает, что слушатель решил упражнение, а корректное решение не должно менять полученный индекс. В карточке назначения храним идентификатор варианта и версию критериев оценки. Если преподаватель исправил опечатку в условии, это отдельная редакция материала с понятной совместимостью. Она не заменяет зафиксированный список скрытно и не создаёт новый розыгрыш для уже зарегистрированного участника.

Проверки сценария

Разберём ожидаемые результаты на бумаге. A относится к Анне, B — к Борису. Ответ B приходит первым: меняется только запись Бориса. Затем приходит A: запись Анны получает свой вариант. Перестановка порядка не влияет на соответствие слушателей.

Далее пытаемся изменить набор вариантов у A после отправки. Операция отклоняется политикой зафиксированной заявки. Затем имитируем ошибку сложного завершения: слово уже сохранено, но назначение ещё не отмечено завершённым. Повтор завершения использует прежнее слово; новый запрос не создаётся. Эти сценарии описывают желаемое поведение, фактического исполнения в этой главе нет.

Наконец, представим, что организатор сам решает, кому разрешено подать заявку. VRF не делает такую политику справедливой автоматически. Проверяемость числа и правила допуска — разные вопросы. В документации библиотеки отдельно объясняем список участников, момент его фиксации и последствия задержки. В следующей главе автоматизируем действия, которым разрешён повтор, сохраняя эту границу для случайного назначения.

Оглавление серии