Solidity: публикация и замена записи в реестре
Все составные части первой изменяющей функции уже известны. Теперь прочитаем publish как полноценный переход выпуска. Важно сохранить её точную семантику: это не только создание курса и не запрет повторов. Издатель может заменить текущий отпечаток и сделать запись активной снова.
Рассмотрим три исходных состояния курса 17: его ещё нет, он активен с H1, он отключён с H1. Один допустимый publish(17,H2) приводит каждое из них к H2,true. Такое правило удобно для исправления материалов, но должно быть явно объявлено читателю.
Полная функция
function publish(uint256 courseId, bytes32 contentHash)
external
onlyPublisher
{
if (courseId == 0 || contentHash == bytes32(0)) {
revert InvalidCourse();
}
courses[courseId] = Course(contentHash, true);
emit Published(courseId, contentHash);
}
Это точный фрагмент базового CourseCatalog. До тела модификатор проверяет непосредственного отправителя. Внутри отвергаются два недопустимых входа. Затем полная структура записывается по ключу, и журнал сообщает тот же номер и отпечаток.
Здесь нет условия if already exists. Добавление такого условия изменило бы договор: публикация исправленного материала перестала бы работать через тот же метод. Нельзя назвать такое изменение только «усилением проверки», не объяснив, какой разрешённый переход теперь запрещён.
С другой стороны, повторное присваивание того же отпечатка тоже допустимо в базовой реализации. Функция может снова создать событие с тем же значением. Если приложению нужно запрещать бессмысленные повторы, это новое требование к отдельному варианту. Исходная модель не обещает одно событие на один уникальный хеш.
Почему номер остаётся стабильным
На сайте адрес курса может быть постоянным, а материалы обновляются. Номер 17 играет похожую роль: это стабильный ключ текущего выпуска. Отпечаток относится к конкретной версии байтов. Такой выбор позволяет обновлять содержание, не менять ссылку на сам курс в каждом меню.
Но стабильный ключ не гарантирует неизменности найденного по нему артефакта. Читатель, которому нужна цитата определённого выпуска, должен сохранить его отпечаток и реквизиты истории. Запрос текущего курса спустя месяц может вернуть уже H3. Для сайта это полезное обновление, для ссылки на прежний результат — другой вопрос.
Поэтому интерфейс может показывать «текущий выпуск» и отдельно «просмотреть историю». Недопустимо назвать обычный изменяемый getter вечной ссылкой на неизменный документ. Имена полей и подписи интерфейса должны соответствовать возможности издателя выполнять замену.
Три начальных состояния
Разберём ожидаемые переходы:
| До вызова | Вызов издателя | После | Значение |
|---|---|---|---|
| Нули,false | publish(17,H2) | H2,true | Первое объявление |
| H1,true | publish(17,H2) | H2,true | Исправленный текущий выпуск |
| H1,false | publish(17,H2) | H2,true | Повторная активация через новый выпуск |
Параметр H2 здесь обозначает ненулевые 32 байта выбранного файла. Если внешний инструмент неверно вычислил отпечаток, контракт не способен сам проверить соответствие без предоставления дополнительных данных. Он обеспечивает право и формат значения, а не читает скрытый Markdown с сервера редактора.
Это граница ответственности процесса выпуска. Редактор готовит артефакт, вычисляет отпечаток и сравнивает его до подписания. Контракт принимает объявление выбранного издателя. Читатель затем самостоятельно сопоставляет полученный файл с объявлением. Ошибка любой части должна объясняться в соответствующем месте.
Успешная транзакция и результат страницы
После отправки редактор получает идентификатор действия и ждёт результат. Возврат хеша не является завершением публикации. Если квитанция показывает отказ, поля остаются прежними. Если действие успешно, другой последующий выпуск мог уже заменить его значение до обновления интерфейса.
Допустим, редакторы работают через одну модель издателя и почти одновременно готовят H2 и H3. Последняя успешная запись побеждает по выбранному порядку. Базовая функция не сравнивает ожидаемый старый отпечаток. Для предотвращения случайной перезаписи потребуется отдельное правило конкуренции, например метод с проверкой прежнего значения. Оно будет введено в расширенной модели, а не приписано этому листингу.
В локальном редакционном интерфейсе можно предварительно показать текущий hash и предупредить о замене. Но предварительное чтение не блокирует чужую публикацию между чтением и исполнением. Это общая причина различать просмотр состояния и условие, проверенное контрактом во время записи.
Варианты неверного входа
Нулевой номер отклоняется. Он не создаёт «главный курс» или общее значение по умолчанию. Нулевой отпечаток также отклоняется: он зарезервирован моделью как отсутствие публикации. Чужой адрес не проходит ещё раньше через проверку роли.
Если courseId очень большой, uint256 может его представить, и базовая проверка ненулевого номера сама по себе не запрещает такой ключ. Это соответствует модели внешних стабильных идентификаторов. Если редакционная система допускает только определённый диапазон, его требуется отдельно согласовать, а не выводить из размера существующего каталога.
Функция не принимает ETH и не обращается к токенам. Поэтому публикация не покупает доступ и не переводит деньги автору. Добавление оплаты создаст другую границу доверия и внешние взаимодействия. На этом этапе право публикации определяется единственным адресом, а ресурсы исполнения относятся к обычной комиссии сети.
Мы собрали точное правило текущего выпуска. Оно остаётся коротким благодаря заранее выбранным типам, состоянию и субъекту полномочий. Следующая страница рассмотрит обратное действие — деактивацию, которое меняет только флаг и сохраняет отпечаток. Функции и состояние Solidity помогают сопоставить эту модель с синтаксисом языка.
Конкурирующие редакционные намерения
Рассмотрим редакторов, которые оба прочитали H1. Первый подготовил H2, второй H3. Базовый контракт принимает допустимые действия издателя в порядке исполнения и не проверяет, что исходное чтение редактора всё ещё актуально. Поэтому позднее действие может заменить ранее опубликованное исправление.
Это не нарушение его текущего договора. Для требуемой защиты нужно новое предусловие: ожидаемый прежний hash либо номер revision. Тогда исполнение сравнивает состояние с ожиданием и при расхождении отклоняет устаревшее намерение. Такой вариант следует назвать новым интерфейсом, а не приписать показанному publish.
Редакционный инструмент может также согласовывать выпуск до отправки, чтобы несколько людей не пользовались одним адресом как несогласованной очередью. Это организационное ограничение дополняет код. Неизменяемый издатель сам по себе не знает, сколько человек действует от его субъекта.
Для самостоятельного разбора поменяйте порядок H2 и H3. У обоих действий допустимые параметры, но конечный hash другой. Такая модель подготавливает к теме порядка транзакций, не требуя сценариев заработка или действий на чужих проектах. Мы исследуем собственный ограниченный реестр и последствия его явно объявленных правил.
Оглавление курса. Листинги, расчёты и наблюдения здесь разобраны как ожидаемое поведение; компиляция, учебные программы и проверки при написании не запускались.