Лучшие практики обеспечения безопасности для контрактов с агентами по бриллиантам

Прокси-контракты — важный инструмент для разработчиков смарт-контрактов. На сегодняшний день в контрактной системе существует множество режимов прокси и соответствующих им правил использования. Ранее мы изложили передовые методы обеспечения безопасности обновляемых прокси-контрактов.

В этой статье мы представим еще одну модель прокси, популярную в сообществе разработчиков, модель прокси-сервера Diamond.

Алмазные прокси-контракты, также известные как «алмазы», представляют собой шаблон проектирования для смарт-контрактов Ethereum, представленный Предложением об улучшении Ethereum (EIP) 2535.

Алмазный режим позволяет контракту иметь неограниченную функциональность, разделяя его функциональность на более мелкие контракты (также удачно называемые «аспектами»). Алмаз действует как прокси, перенаправляя вызовы функции на соответствующий аспект.

Дизайн ромбовидной модели может решить проблему ограничения максимального размера контракта в сети Ethereum. Разбивая большой контракт на более мелкие аспекты, ромбовидный шаблон позволяет разработчикам создавать более сложные и многофункциональные смарт-контракты, не влияя на ограничения по размеру.

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

В этой статье представлен обзор EIP-2535, включая сравнение с широко используемым режимом прозрачного прокси-сервера и режимом прокси-сервера UUPS, а также соображения безопасности для сообщества разработчиков.

В контексте EIP-2535 «алмаз» — это прокси-контракт, функциональная реализация которого обеспечивается различными логическими контрактами, называемыми «аспектами».

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

Алмазный стандарт использует аналогию для расширения возможностей «алмазной огранки» для добавления, замены или удаления граней и функций.

Кроме того, Diamond Standard предоставляет функцию под названием «Алмазная лупа», которая возвращает информацию о гранях и наличии бриллианта.

По сравнению с традиционной прокси-моделью «ромб» эквивалентен прокси-контракту, а различные «аспекты» соответствуют реализации контракта. Различные аспекты алмазного агента могут совместно использовать внутренние функции, библиотеки и переменные состояния. Ключевые компоненты бриллианта следующие:

Центральный контракт, который действует как прокси, перенаправляет вызовы функции к соответствующему аспекту. Он содержит отображение селекторов функций на «аспектные» адреса.

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

представляет собой набор стандартных функций, определенных в EIP-2535, которые предоставляют информацию о селекторах граней и функций, используемых в бриллиантах. Алмазная лупа позволяет разработчикам и пользователям изучать и понимать структуру бриллиантов.

Функции для добавления, замены или удаления граней в бриллианте и соответствующие селекторы функций. Только авторизованные адреса (например, владелец бриллианта или контракт с несколькими подписями) могут выполнять огранку бриллианта.

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

Все прокси используют функцию fallback() для делегирования вызовов функций внешним адресам. Ниже представлена реализация алмазного прокси и реализация традиционного прокси.

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

Основное отличие состоит в том, что в алмазном прокси адрес аспекта определяется по хеш-карте от msg.sig (селектора функций) вызывающей стороны до адреса аспекта, в то время как в традиционном прокси адрес импл не зависит от вход звонящего.

Резервная функция алмазного агента

Традиционная резервная функция прокси

Сопоставление SelectorToFacet определяет, какой контракт содержит реализацию каждого селектора функций. Работникам проекта часто приходится добавлять, заменять или удалять это сопоставление селектора функций и контракта реализации. EIP-2535 предусматривает: для достижения этой цели должна быть функция diamondCut(). Ниже приведен пример интерфейса.

Каждая структура FacetCut содержит адрес фасета и четырехбайтовый массив селекторов функций, которые необходимо обновить в алмазном прокси-контракте. FaceCutAction позволяет добавлять, заменять и удалять селекторы функций. Реализация функции diamondCut() должна включать адекватный контроль доступа, предотвращение коллизий слотов, восстановление после сбоя и т. д.

Чтобы узнать, какие функции и грани имеет алмазный агент, мы используем «алмазную лупу». «Алмазная лупа» — это особый аспект, который реализует следующий интерфейс, определенный в EIP-2535:

Функция Facets() должна возвращать адреса всех фасетов и их четырехбайтовых селекторов функций. Функция facetFunctionSelectors() должна возвращать все селекторы функций, поддерживаемые определенным аспектом. Функция facetAddresses() должна возвращать все адреса граней, используемые бриллиантом.

Функция facetAddress() должна возвращать аспект, который поддерживает данный селектор, или адрес (0), если он не найден. Обратите внимание, что не должно быть более одного адреса аспекта с одним и тем же селектором функций.

Учитывая, что алмазные прокси-серверы делегируют разные вызовы функций разным контрактам реализации, очень важно правильно управлять слотами хранения, чтобы предотвратить конфликты. EIP-2535 упоминает несколько методов управления слотами хранения.

Этот аспект может объявлять переменные состояния в структуре. Этот аспект может использовать любое количество структур, каждая из которых имеет свое место хранения. Каждая структура имеет определенное место в хранилище контрактов. Аспекты могут объявлять свои собственные переменные состояния, но они не могут конфликтовать с местами хранения переменных состояния, объявленными другими аспектами. Образец библиотеки и контракт на хранение бриллиантов представлены в EIP-2535, как показано на следующем рисунке:

Хранилище приложений — это более специализированная версия алмазного хранилища. Этот шаблон используется для более удобного и легкого совместного использования переменных состояния аспектов. Структура магазина приложений содержит любое количество и тип переменных состояния, необходимых приложению. Аспект всегда объявляет структуру AppStorage как первую и единственную переменную состояния в позиции 0 слота хранилища. Затем различные аспекты могут получить доступ к переменным из этой структуры.

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

Сравнение с прозрачным прокси-сервером и прокси-сервером UUPS

В настоящее время сообщество разработчиков Web3 использует два основных режима прокси: режим прозрачного прокси и режим прокси UUPS. В этом разделе мы кратко сравним режим алмазного прокси с режимами прозрачного прокси и прокси UUPS.

1.ЭПИ-2535:

2.ЭПИ-1967:

3.Эталонная реализация прокси-сервера Diamond:

4.Реализация OpenZeppelin:

Прокси и масштабируемые решения представляют собой более сложные системы, и OpenZeppelin предоставляет базы кода и исчерпывающую документацию для масштабируемых прокси UUPS, Transparent и Beacon. Однако для режима алмазного прокси, несмотря на то, что OpenZeppelin подтвердили его преимущества, они все же решили не включать реализацию алмаза EIP-2535 в свою библиотеку.

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

Разбивая логику контракта на более мелкие, более управляемые модули, разработчики могут легче тестировать и проверять свой код.

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

Источник: Аавегочи Гитхаб

Когда алмазный прокси-контракт развернут, он должен добавить адрес алмазного прокси-контракта в алмазный прокси-контракт и реализовать функцию diamondCut(). Функция diamondCut() используется для добавления, удаления или замены фасетов и функций, без DiamondCutFacet и diamondCut() алмазный агент не может работать должным образом.

Источник: Diamond-3-Hardhat Мугена

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

Шаблон AppStorage требует, чтобы для алмазного прокси была объявлена одна и только одна структура, и чтобы эта структура была общей для всех аспектов. Если требуется несколько структур, следует использовать шаблон DiamondStorage.

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

Обходной путь заключается в добавлении новых переменных состояния в отображаемую в память структуру вместо помещения «структуры» непосредственно в «структуру». Слоты хранения переменных на карте вычисляются по-разному и не являются смежными в хранилище.

На размер массива будет влиять размер структуры. Когда в структуру добавляется новая переменная состояния, она изменяет размер и расположение этой структуры.

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

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

Функция initialize() обычно используется для установки важных переменных, таких как адреса привилегированных ролей. Если он не инициализирован при развертывании контракта, злоумышленник может вызвать контракт и управлять им.

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

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

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

Однако дополнительная гибкость может также означать более широкую поверхность атаки для злоумышленников. Мы надеемся, что эта статья поможет сообществу разработчиков понять механику алмазной прокси-модели и ее аспекты безопасности.

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

Посмотреть Оригинал
Содержание носит исключительно справочный характер и не является предложением или офертой. Консультации по инвестициям, налогообложению или юридическим вопросам не предоставляются. Более подробную информацию о рисках см. в разделе «Дисклеймер».
  • Награда
  • комментарий
  • Поделиться
комментарий
0/400
Нет комментариев
  • Закрепить