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

Foundry: исходники, настройки и байткод контракта

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

Подготовим паспорт артефакта и разберём различие кода создания и runtime. Сборка, размещение и сравнение байткода пока не выполнялись, поэтому готового артефакта, вычисленного хеша или подтверждённого production-экземпляра у главы нет. Результат — понятный набор сведений для будущей сверки.

Исходный файл не является исполняемым экземпляром

Solidity-компилятор преобразует исходники в код по определённым настройкам. На результат влияют версия компилятора, целевой EVM, optimizer, подключённые исходники и параметры метаданных. Поэтому копии одного текста с разными профилями могут создавать разные артефакты.

Кроме того, при размещении наш конструктор получает адрес издателя. Поле publisher объявлено immutable, и значение становится частью конфигурации runtime экземпляра. Два реестра с разными издателями не следует автоматически считать побайтно одинаковыми только из-за общего исходного файла.

Имя и ABI описывают интерфейс, но не доказывают реализацию. Другая программа может предоставлять courses и publish с теми же типами, нарушая правила роли или сохранения digest. Для происхождения нужны артефакт, параметры создания, адрес и сеть вместе.

Код создания выполняет конструктор

Creation bytecode используется при создании программы. Он выполняет логику конструктора и возвращает код, который будет сохранён у нового адреса. Runtime bytecode — это программа последующих обращений. Хеш первой величины не является автоматически хешем второй.

Аргументы конструктора передаются в ABI-форме после кода создания. Для нашего типа это один адрес. Следующий фрагмент показывает, как собрать такой вход в Solidity; он не отправляет транзакцию и не утверждает, что соответствующее размещение уже произошло.

bytes memory initCode = abi.encodePacked(
    type(CourseCatalog).creationCode,
    abi.encode(publisher)
);

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

Один и тот же адрес издателя должен совпадать в паспорте, ABI-аргументах и наблюдаемом getter. Если вместо адреса записать неправильные байты, интерфейс ожидания может не соответствовать экземпляру. Поэтому параметр создания не стоит оставлять только в случайной заметке после развёртывания.

Immutable требует конкретной конфигурации

Для программ с immutable нельзя без анализа сравнить шаблон runtime из компилятора с кодом любого экземпляра. Значения подставляются в соответствующие места при создании. В артефакте могут присутствовать сведения о ссылках immutable, но точная схема зависит от инструмента и версии.

Наша задача — получить ожидаемый код для согласованных исходников и параметров, затем сравнить его с наблюдаемым runtime. Не заменяем эту процедуру утверждением code.length > 0: наличие кода лишь исключает пустой адрес и ничего не говорит о его прикладном договоре.

Также не предлагаем механически использовать type(CourseCatalog).runtimeCode как универсальный шаблон для данного immutable-контракта. Подобная работа имеет ограничения языка и конфигурации. Надёжный план должен учитывать реальные артефакты выбранной версии компилятора и подстановку параметров.

Собираем паспорт исходников

Для будущей сборки сохраняем точную редакцию CourseCatalog.sol, набор зависимостей, версию компилятора и весь существенный профиль. Номер урока помогает человеку найти объяснение, но не заменяет неизменный идентификатор исходных файлов, по которым получен артефакт.

Группа Что сохраняется Зачем
Исходники Файлы и их редакция Повторить вход компилятора
Компилятор Версия и фактическая сборка Повторить преобразование
Настройки EVM, optimizer, метаданные Получить сопоставимый код
Конструктор Адрес издателя и ABI-байты Восстановить конфигурацию
Экземпляр Сеть, адрес, блок наблюдения Найти конкретное состояние

Наш подготовленный профиль указывает Solidity 0.8.30, EVM cancun и выключенный optimizer. Он не доказывает, что соответствующий бинарный компилятор уже установлен. В фактическом отчёте должны появиться использованные значения, а не только ожидаемые параметры статьи.

Метаданные тоже имеют происхождение

Solidity может добавлять сведения о метаданных в байткод. Изменение исходного текста или настроек способно повлиять на эти сведения, даже если человек считает прикладную логику неизменной. Поэтому побайтовое отличие надо исследовать, а не сразу объяснять дефектом алгоритма реестра.

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

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

Отпечаток runtime и отпечаток учебника

Для наблюдаемого кода в локальном сценарии можно вычислить keccak256(address(catalog).code). Это хеш runtime конкретного экземпляра в выбранном состоянии. Он не является contentHash учебного выпуска и не заменяет SHA-256 сохранённых байтов манифеста.

В паспорте названия должны различать эти величины: например, runtimeCodeHash и manifestDigest. Если оба назвать просто hash, читатель может сравнить несовместимые данные и ошибочно признать программу или выпуск неподлинными. Алгоритм и вход записываются рядом с каждым отпечатком.

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

Разбираем изменённый пример

Если поменять publisher с 0xA11CE на другой адрес, требования методов могут остаться прежними, но полномочие и runtime-конфигурация изменятся. Unit-сценарии должны использовать новый согласованный адрес, а паспорт экземпляра — новый аргумент. Старый отчёт больше не описывает новую конфигурацию.

Если поменять optimizer, результат анализа газа также может измениться. Поэтому происхождение артефакта связывает сравнение поведения, стоимость и идентичность программы. Этот договор особенно важен перед будущим размещением, когда локальные файлы должны соответствовать выбранному адресату транзакций.

В следующем уроке соберём полный комплект и отчёт о границах. Метаданные описаны в Solidity 0.8.30, свойства immutable — в разделе контрактов. Оглавление курса.

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