IPFS: манифест и CourseCatalog
Манифест описывает выпуск, а CourseCatalog объявляет его от имени издателя. Теперь соединим два механизма так, чтобы CID не смешивался с полем bytes32. В уроке определим маршрут проверки от записи реестра до файлов библиотеки и разберём ограничения хранения только одного текущего отпечатка.
Используем базовый контракт из обзорного материала: publisher, courses, publish, deactivate, события Published и Deactivated. Его исходный смысл не меняется. Мы не развёртываем контракт, не вычисляем SHA-256 и не отправляем транзакции.
Согласованное обязательство
Поле contentHash базового контракта хранит 32 байта. Сам контракт не определяет алгоритм. Для библиотеки выбрано значение SHA-256 точных сохранённых байтов манифеста выпуска. Это соглашение приложения, которое должно быть известно и издателю, и проверяющему клиенту.
CID хранится отдельно в досье и способах обнаружения. Он содержит структуру, которую нельзя без объяснения обрезать до bytes32. Если digest одного структурного блока совпадает по длине с SHA-256 манифеста, это ещё не значит, что оба относятся к одинаковым байтам.
release.json bytes ──SHA-256──→ CourseCatalog.contentHash
│
└─ импорт IPFS ──────→ MANIFEST_CID
каталог выпуска ─────────────→ ROOT_CID
Схема подчёркивает три значения. SHA-256 относится к файлу. CID манифеста относится к его выбранному block/DAG-представлению. Корень каталога описывает полный набор, включая ссылки на файлы. Досье связывает их, не выдавая одно за другое.
Подготовка объявления
Издатель фиксирует байты release.json, архивирует их и вычисляет обязательство. Затем получает CID при выбранном профиле импорта и обеспечивает хранение достаточного набора блоков. Лишь после этого подготовленное объявление готово к согласованию.
Если объявить отпечаток до обеспечения доступности, читатели могут увидеть подлинную запись, но не получить файл. Поэтому процедура публикации включает разные стадии: подготовлено, импортировано, сохранено, объявлено. Совпадение криптографического значения не гарантирует доступность ни одной реплики.
Сама транзакция publish(17, digest) требует полномочия издателя. Клиент проверяет сеть и адрес экземпляра контракта, потому что другой реестр может иметь те же функции и другое назначение. ABI помогает прочитать поля, но не удостоверяет организационную принадлежность адреса.
Проверка читателем
Читатель получает текущую запись курса и видит активность. Затем обнаруживает манифест по согласованному CID или HTTP-ссылке, получает байты и сравнивает SHA-256 с объявленным значением. Только после совпадения разбирает схему и проверяет необходимые файлы.
Если файл получен через обычный HTTP, независимая файловая проверка всё равно полезна: место выдачи не обязано быть доверенным для изменения содержания. Если клиент получает проверенный DAG, проверка CID подтверждает структурное содержание, а сопоставление с обязательством реестра устанавливает связь с объявлением издателя.
Не доверяем поле contentHash, присланное самим шлюзом рядом с файлом, вместо чтения согласованного реестра. Такая пара может быть внутренне правильной для чужого выпуска. Канал доверия начинается с известной сети, адреса и правил издателя.
Активность и отзыв
deactivate(17) меняет активность записи по базовому контракту. Оно не удаляет манифест из IPFS и не заставляет хранителей уничтожить копии. Клиент может показать, что издатель больше не рекомендует этот выпуск, сохранив возможность исторического анализа.
Если материалы уже скачаны, изменение реестра не отменяет знание байтов. Поэтому отзыв пригоден для текущей рекомендации и будущих действий приложения, а не для гарантированного физического стирания. Этот принцип важен и для платного доступа: после выдачи открытого файла контроль копирования ограничен.
Публичное чтение реестра не требует подключения кошелька. Подпись пользователя нужна для определённых записей или авторизации, но просмотр объявления может использовать независимый публичный клиент. Веб-курс подробно рассматривает это разделение; здесь мы определяем семантику данных.
Текущая версия и история
Базовая структура курса хранит текущий отпечаток и активность. Повторный publish по номеру курса может обновить текущую запись согласно исходному контракту. Она не превращается автоматически в полный реестр всех редакций.
Если библиотеке нужна адресация каждой версии, потребуется явное расширение модели либо индексирование событий и внешнее досье. В этом уроке не добавляем новый метод молча. Сохраняем названия edition=1, edition=2 в манифестах и архивируем объявленные записи с их сетевым контекстом.
Клиент, который открывает старый выпуск, должен понимать, проверяет ли он текущую рекомендацию или историческое объявление. Совпадение со старым событием и совпадение с текущим полем — разные утверждения. При реорганизации индексатор пересматривает принадлежность события выбранной истории.
Старое объявление и текущий выбор
Пусть первая редакция объявлена событием Published, затем для того же курса опубликована вторая. Читатель сохранил первую и хочет подтвердить её происхождение. Текущее поле courses(17) уже может содержать другое обязательство. Это не делает первую редакцию поддельной: требуется исторический маршрут с конкретным событием и его принадлежностью принятой цепочке. Интерфейс должен назвать проверяемое утверждение — исторически объявлено или сейчас активно рекомендовано.
Сохранённый ответ RPC без контекста недостаточен для такого различия. В досье исторического объявления полезны сеть, адрес контракта, номер и хеш блока, идентификатор транзакции и позиция события. При реорганизации индексатор способен пересмотреть этот ответ. Если приложение поддерживает только чтение текущего состояния, оно сообщает ограничение, а не обещает подтверждение всех прежних редакций по одному текущему полю.
Теперь предположим, что изменяемое имя IPNS ещё ведёт к первой редакции, а реестр уже объявил вторую. Клиент получает подлинный старый манифест, но его SHA-256 не совпадает с текущим обязательством. Нельзя отключить сравнение ради успешной загрузки. Можно повторить разрешение имени или воспользоваться другим объявленным способом получения. Если пользователь сознательно открыл архив, приложение переключает именно режим проверки, сохраняя указание старой версии.
Таким образом, CID помогает назвать материал, а сетевой контекст реестра и редакционная политика определяют его положение в истории. Неявное смешение этих слоёв создаёт ложные выводы о повреждении или актуальности. В нашей модели базовый контракт остаётся прежним: история и способы обнаружения описываются рядом, без выдуманного метода для версий. Это позволяет точно объяснить, какую гарантию уже даёт связка манифеста и текущего состояния, а какая требует дополнительного архивного индекса.
Результат связи
Для собственного досье создаём запись: курс, редакция, алгоритм обязательства, точные байты манифеста, CID манифеста, корень каталога, сеть и адрес реестра. Пока значения не вычислены и транзакция не отправлена, состояние остаётся подготовленным.
Официальные основы доступны в документации CID и ABI Solidity. Сам базовый пример разобран в обзоре Solidity. Теперь цепочка проверки имеет явные основания, а адрес хранения не подменяет 32-байтовое обязательство относительно файла.