AI Прокси контракты, как они работают, какие бывают и как это работает в EVMPack. Часть 1

AI

Редактор
Регистрация
23 Август 2023
Сообщения
2 959
Лучшие ответы
0
Реакции
0
Баллы
51
Offline
#1

Прокси-контракты: Сравнение подходов OpenZeppelin и EVMPack


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

Что такое прокси-контракт?


Прокси-контракт - это простой контракт-переадресатор. Он хранит адрес основного, "логического" контракта. При вызове функции на прокси, он перенаправляет вызов (через delegatecall) на контракт с логикой.

Особенность delegatecall в том, что код исполняется от имени прокси-контракта, то есть в его контексте хранилища (storage). Это позволяет менять адрес контракта с логикой, в то время как все данные (состояние) остаются на адресе прокси. Для обновления достаточно просто указать прокси новый адрес реализации.

Классический подход: Hardhat + OpenZeppelin


Самый популярный стек для разработки - это Hardhat в связке с плагинами от OpenZeppelin. Плагин hardhat-upgrades значительно упрощает работу с прокси, абстрагируясь от ручного развертывания всех необходимых компонентов.

Рассмотрим реальный код из теста для контракта Blog.

Пример 1: Процесс, управляемый с клиента


Вот как выглядит развертывание прокси с помощью плагина в JavaScript-тесте:

// test/Blog.js

const { upgrades, ethers } = require("hardhat");

// ...

describe("Blog", function () {
it("deploys a proxy and upgrades it", async function () {
const [owner] = await ethers.getSigners();

// 1. Получаем фабрику контракта
const Blog = await ethers.getContractFactory("Blog");

// 2. Деплоим прокси. Плагин сам:
// - развернет контракт логики Blog.sol
// - развернет контракт ProxyAdmin
// - развернет прокси и свяжет все вместе
const instance = await upgrades.deployProxy(Blog, [owner.address]);
await instance.deployed();

// ... тут идут проверки ...

// 3. Апгрейд на вторую версию
const BlogV2 = await ethers.getContractFactory("BlogV2");
const upgraded = await upgrades.upgradeProxy(instance.address, BlogV2);

// ... и снова проверки ...
});
});


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

Ончейн-подход: EVMPack


EVMPack переносит логику оркестрации ончейн, действуя как ончейн-менеджер пакетов, аналогично npm или pip.

Пример 2: Ончейн-фабрика EVMPack


Предположим, разработчик Blog зарегистрировал свой пакет в EVMPack под именем "my-blog". Любой пользователь или другой смарт-контракт может создать экземпляр блога одной транзакцией через фабрику EVMPackProxyFactory:

// Вызываем одну функцию в контракте EVMPackProxyFactory

// EVMPackProxyFactory factory = EVMPackProxyFactory(0x...);

address myBlogProxy = factory.usePackageRelease(
"my-blog", // 1. Имя пакета
"1.0.0", // 2. Нужная версия
msg.sender, // 3. Адрес владельца
abi.encodeWithSignature("initialize()"), // 4. Данные для инициализации
"my-first-blog" // 5. Соль для предсказуемого адреса
);

// Переменная myBlogProxy содержит адрес готового к работе прокси.
// Фабрика самостоятельно создала прокси, его админа и связала их с логикой.


Важно понимать, что вызывать usePackageRelease можно не только из другого контракта. Представьте себе веб-интерфейс (dApp), где пользователь нажимает кнопку "Создать мой блог". Ваш JavaScript-клиент, используя ethers.js, делает одну транзакцию - вызов этой функции. В результате пользователь с ходу получает готовое "приложение" на стороне блокчейна - его личный, обновляемый экземпляр контракта. К тому же, это очень экономно по газу, так как каждый раз разворачивается только легковесный прокси-контракт (и опционально его админ), а не вся тяжеловесная логика реализации. Да, останется задача отрисовать для него UI, но это уже другая история. Главное - мы заложили мощную и гибкую базу.

Процесс, который ранее был в JS-скрипте, теперь находится ончейн, стандартизирован и доступен для всех участников сети.

Сравнение подходов

Критерий​

Hardhat + OpenZeppelin​

EVMPack​

Где логика?

На клиенте (в JS-скрипте).​

Ончейн (в контракте-фабрике).​

Кто может вызвать?

Тот, у кого есть скрипт и зависимости.​

Любой пользователь или смарт-контракт.​

Поиск кода

Внеблокчейновый. Нужно знать, какой контракт деплоить.​

По имени и версии ("my-blog@1.0.0").​

Процесс деплоя

Серия транзакций с клиента.​

Атомарный. Одна ончейн-транзакция.​

Изоляция

Один ProxyAdmin может управлять многими прокси.​

Фабрика создает отдельного админа для каждого прокси.​

Философия

Инструмент для разработчика.​

Публичная ончейн-инфраструктура.​


А как обновляться?


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

Этот контракт-админ не обращается к реестру EVMPack напрямую. Вместо этого он дает команду самому прокси-контракту обновиться до указанной версии.

// Допустим, разработчик "my-blog" выпустил версию 1.1.0
// Владелец прокси (owner) вызывает функцию на своем контракте EVMPackProxyAdmin

IEVMPackProxyAdmin admin = IEVMPackProxyAdmin(myBlogProxyAdminAddress);

// Владелец указывает, какой прокси-контракт нужно обновить,
// до какой версии, и опционально передает данные для вызова
// функции инициализации на новой версии.
admin.upgradeAndCall(
IEVMPackProxy(myBlogProxyAddress), // Адрес нашего прокси
"1.1.0", // Новая версия из реестра
"" // Данные для вызова (если не нужны - пустая строка)
);

// Готово! Прокси сам, зная имя своего пакета, обратится к реестру EVMPack,
// проверит новую версию, получит адрес реализации и обновится.
// Состояние контракта при этом сохранится.


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

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

Преимущества ончейн-фабрики


Подход EVMPack превращает создание прокси в публичный, компонуемый ончейн-сервис. Это создает новые возможности:


  • DeFi протоколы, позволяющие пользователям создавать изолированные обновляемые хранилища.


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


  • NFT-проекты, где каждая NFT может быть прокси с кастомизируемой логикой.

Это делает ончейн-код по-настоящему переиспользуемым, по аналогии с npm-пакетами.

Итог


Плагин hardhat-upgrades - это эффективный инструмент, решающий задачу для разработчика.

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

В следующей части разберём Beacon прокси

Следить за активной разработкой инструмента можно на гитхабе или в ТГ канале
 
Сверху Снизу