Foundry: структура проекта и профиль лаборатории
Учебная библиотека будет объявлять выпуски курсов через контракт. Прежде чем исследовать его поведение, подготовим место, где исходники, требования и настройки не смешиваются. Результатом первого урока станет понятная структура проекта и зафиксированный профиль среды. Контракт и проверки добавим после этого, когда будет ясно, какие файлы относятся к приложению, а какие — к исследованию.
Для чтения полезны основы Solidity и командной строки. Если язык пока незнаком, начните с курса о реестре публикаций. Здесь мы не устанавливаем программы и не выполняем команды: исходники и ожидаемые эффекты предназначены для будущей самостоятельной локальной работы. Такой статус сохраняется во всём курсе, поэтому конфигурация проекта не является отчётом об успешном прогоне.
Отделяем программу от её проверки
Foundry включает несколько инструментов. Forge работает с проектом, компиляцией и проверками, Anvil предоставляет отдельную учебную сеть, Cast помогает обращаться к EVM-интерфейсам. В первых уроках нужен прежде всего Forge. Подключённый кошелёк и публичный RPC для простого сценария поведения контракта не требуются: проверяющая среда создаёт собственные экземпляры и задаёт их контекст.
При этом проверка не становится методом действующего контракта. Функция, которая назначает отправителя или ожидает откат, существует в специальной среде. Посетитель сайта не получает её вместе с ABI реестра. Это различие важно уже при выборе каталогов: мы не хотим случайно считать учебный вспомогательный код частью приложения.
Создадим проект library-quality со следующей предполагаемой структурой. Каталоги зависимостей и результатов пока могут отсутствовать; дерево объясняет их будущую роль.
library-quality/
foundry.toml
remappings.txt
README.md
src/
CourseCatalog.sol
test/
CourseCatalog.t.sol
lib/
forge-std/
out/
cache/
src содержит программу библиотеки, test — сценарии проверки. lib предназначен для закреплённых зависимостей. В out и cache инструмент может создавать результаты своей работы; это производные данные. Они не заменяют исходный контракт и не должны использоваться как единственное свидетельство того, какой вариант программы исследовался.
Названия файлов тоже несут смысл. Суффикс .t.sol помогает узнать учебный файл проверки, хотя окончательное обнаружение зависит от соглашений инструмента. Вместо набора файлов test1, test2 полезнее использовать имя исследуемого объекта. Позже появятся разные виды сценариев, и их можно будет разделить по назначению, сохраняя один базовый контракт.
Фиксируем профиль, а не слово latest
Наш учебный профиль продолжает существующую лабораторию ProfessorWeb: Solidity 0.8.30, Foundry 1.3.1 и целевая EVM Cancun. Для библиотеки проверок отдельно выбираем forge-std 1.9.7. Это известные версии примера, а не заявление, что они являются последними или автоматически подходят действующему финансовому сервису.
Версия Forge и версия forge-std — разные записи. Обновив исполняемый инструмент, вы не обязаны получить новую библиотеку Solidity в lib, и наоборот. Поэтому в описании проекта недостаточно написать «установлен Foundry». Нужно знать, какой компилятор использовался, какой код импортирован и какие настройки повлияли на полученные инструкции.
Полный начальный foundry.toml зададим так:
[profile.default]
src = "src"
test = "test"
out = "out"
libs = ["lib"]
solc_version = "0.8.30"
evm_version = "cancun"
optimizer = false
Отключённая оптимизация здесь упрощает исходный профиль. Позже мы отдельно обсудим сравнение расхода газа и артефактов; изменение оптимизации будет явным изменением условий. Оно не должно происходить одновременно с исправлением логики без записи в отчёте, иначе станет трудно понять причину различий.
Файл remappings.txt связывает имя импорта с каталогом закреплённой библиотеки:
forge-std/=lib/forge-std/src/
Когда проверка импортирует forge-std/Test.sol, этот маршрут указывает, где искать файл. Он не скачивает библиотеку и не подтверждает, что в каталоге действительно лежит выбранный тег. Происхождение зависимости нужно сохранить отдельно. В будущем читатель сможет добавить именно версию 1.9.7 из официального репозитория; в текущей подготовке зависимость не установлена и её код не исполнялся.
Что записываем в описание проекта
README лаборатории должен отвечать на три вопроса: что исследуется, какой профиль нужен и что уже выполнено. Для нашего примера достаточно указать реестр курсов, зафиксированные версии и состояние «исходники подготовлены, исполнение отсутствует». Не следует заранее писать, что проверки прошли или что контракт развёрнут, если этих действий не было.
| Запись | Пример | Зачем она нужна |
|---|---|---|
| Назначение | Реестр текущего выпуска курса | Отделяет объект исследования от других проектов |
| Компилятор | Solidity 0.8.30 | Определяет перевод языка в инструкции |
| Среда | Foundry 1.3.1, Cancun | Фиксирует инструмент и целевые правила исполнения |
| Библиотека | forge-std 1.9.7 | Объясняет доступные утверждения и помощники |
| Статус | Не запускалось | Отделяет ожидание от наблюдаемого результата |
Сохранение номера версии в тексте не означает закрепления файла. Полезно фиксировать тег или ревизию зависимости и проверять, что следующий разработчик получает тот же исходник. Этот принцип одинаков для маленькой лаборатории и большой команды: описание среды помогает воспроизведению лишь тогда, когда соответствует реальным файлам.
Типичные неоднозначности среды
Представим, что два читателя создали одинаковый CourseCatalog.sol, но один использует другую целевую EVM. Их артефакты или доступные инструкции могут отличаться даже при одинаковом тексте контракта. Другая ситуация — одна библиотека проверок подставлена по нескольким маршрутам. Импорт выглядит привычно, но фактически ведёт к неожиданному экземпляру зависимости.
Поэтому диагностику начинаем с профиля и разрешения импортов, а не с попытки изменить случайную строку контракта. Ошибка отсутствующего Test.sol не говорит, что неверно реализована публикация курса. Она означает, что проверяющая среда ещё не получила необходимое определение. Смешение этих двух уровней часто ведёт к ненужным изменениям приложения.
Ещё одна граница — локальная сеть. Для unit-сценариев не нужно заранее подключаться к Anvil только потому, что он входит в Foundry. В последующих уроках появится отдельное упражнение с копией состояния выбранного локального блока. До этого адреса ролей являются учебными значениями внутри проверки, а не реквизитами реальных кошельков.
Сейчас ожидаемый результат — сохранённые файлы профиля и ясное назначение каталогов. Мы не получили байткод, статистику газа или строку успешного запуска; такие сведения нельзя вывести из одного наличия конфигурации. В следующем уроке зададим сам контракт и разрешённые переходы его состояния, чтобы проверять определённое поведение.
Версии инструментов описаны на страницах Foundry 1.3.1 и forge-std 1.9.7. Общий маршрут находится в оглавлении курса.