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

Solidity: задержанная передача главного администратора

Главный администратор обычного AccessControl управляет назначениями и собственной ролью. Ошибка при передаче или отказе может остановить редакцию. Для более определённой процедуры OpenZeppelin предоставляет AccessControlDefaultAdminRules. Этот механизм относится именно к DEFAULT_ADMIN_ROLE и не превращает все публикации в timelock-операции.

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

Один специальный администратор

Расширение хранит действующего главного администратора и ожидающую передачу с расписанием. Обычные grantRole и revokeRole для DEFAULT_ADMIN_ROLE не служат прямой заменой специального маршрута. Это уменьшает число способов неожиданного назначения главного субъекта.

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

Самостоятельный реестр

// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import {AccessControlDefaultAdminRules} from
    "@openzeppelin/contracts/access/extensions/AccessControlDefaultAdminRules.sol";

contract DelayedEditorialCatalog is AccessControlDefaultAdminRules {
    error InvalidAccount();
    error InvalidCourse();
    error NotActive();
    bytes32 public constant PUBLISHER_ROLE = keccak256("PUBLISHER_ROLE");
    bytes32 public constant REVOKER_ROLE = keccak256("REVOKER_ROLE");
    struct Course { bytes32 contentHash; bool active; }
    mapping(uint256 => Course) public courses;
    event Published(uint256 indexed courseId, bytes32 contentHash);
    event Deactivated(uint256 indexed courseId);

    constructor(address admin, address publisher_, address revoker)
        AccessControlDefaultAdminRules(1 days, admin)
    {
        if (publisher_ == address(0) || revoker == address(0)) {
            revert InvalidAccount();
        }
        _grantRole(PUBLISHER_ROLE, publisher_);
        _grantRole(REVOKER_ROLE, revoker);
    }
    function publish(uint256 id, bytes32 digest)
        external onlyRole(PUBLISHER_ROLE)
    {
        if (id == 0 || digest == bytes32(0)) revert InvalidCourse();
        courses[id] = Course(digest, true);
        emit Published(id, digest);
    }
    function deactivate(uint256 id) external onlyRole(REVOKER_ROLE) {
        if (!courses[id].active) revert NotActive();
        courses[id].active = false;
        emit Deactivated(id);
    }
}

Первоначальный admin проверяется базовым конструктором. Собственные адреса операционных ролей проверяются нашим кодом. Мы не выдаём DEFAULT_ADMIN_ROLE второму адресу через _grantRole: расширение имеет специальное правило для этой роли. Издатель и revoker по-прежнему отдельные субъекты.

Начало и принятие

Действующий A вызывает beginDefaultAdminTransfer(N). Появляется ожидающий адрес и время. Само начало не меняет главного администратора. N должен позднее выполнить acceptDefaultAdminTransfer() после прохождения расписания по точным правилам закреплённого исходника.

defaultAdmin=A
beginDefaultAdminTransfer(N)
pendingDefaultAdmin=(N,schedule)
До прохождения schedule: принятие отклоняется
После допустимой границы: N принимает, defaultAdmin=N

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

Чужой адрес не принимает назначение вместо N. Действующий администратор может отменить незавершённую передачу предусмотренным методом. Такая отмена не отзывает операционные роли PUBLISHER и REVOKER автоматически: они имеют собственные назначения.

Задержка не охватывает все действия

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

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

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

Изменение задержки и отказ

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

Добровольный отказ от DEFAULT_ADMIN_ROLE также специальный: требуется предусмотренная последовательность с нулевым будущим адресом и ожиданием. После окончательного отказа обычный главный управляющий отсутствует. Это не назначение всей редакции главными администраторами.

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

Что показывает панель

Интерфейс читает defaultAdmin, pendingDefaultAdmin, defaultAdminDelay и необходимые роли. Он различает текущую власть, предложенную передачу и готовность принятия. Ошибка чтения не означает отмену. Таймаут после отправки не доказывает, что N уже принял управление.

Для упражнения сохраните A и N как разные субъекты, начните передачу, отмените её, затем предложите M. Старый N не должен принять прежнее назначение. Текущее расписание и адрес определяют результат, а не копия формы первой попытки.

Мы получили специальную процедуру главной роли и ясно отделили её от операционных действий. Следующая страница введёт паузу отдельных методов, где тоже важно определить, что именно остановлено. Исходник AccessControlDefaultAdminRules 5.4.0 фиксирует расписание и защищённые маршруты.

Промежуточный период и операционная команда

Во время ожидающей передачи A сохраняет главную роль. Предположим, он назначил дополнительного издателя P2 до принятия N. После смены admin роль P2 не исчезает автоматически: передача главного субъекта не означает очистку всех назначений. Новая команда должна прочитать актуальный состав и решить, что сохранить.

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

Для граничного разбора возьмите schedule=S. На timestamp=S закреплённое условие ещё не прошло, на более позднем допустимом времени может пройти. Это отличие от TimelockController, у которого собственная модель готовности. Нельзя заменить обе реализации одним универсальным ожиданием >= без чтения исходников.

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

Если будущий администратор является контрактом, принятие должно быть доступно его разрешённому маршруту. Ожидание не создаёт этот метод автоматически. До начала процедуры полезно документировать, каким действием N примет право, и кто способен согласовать его внутри N. Иначе аккуратная задержка закончится не завершением передачи, а неопределённым ожиданием. Текущее предложение полезно сопоставлять с полной строкой адреса: сокращённая подпись не позволяет проверить реквизиты принятия самостоятельно.

Для самостоятельного уточнения: AccessControlDefaultAdminRules.sol (5.4.0).

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

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