| Уровень | Вопрос | Evidence |
|---|---|---|
| Deployment | Какой код исполняется на этом block | chain ID, address, bytecode и proxy implementation |
| Role ID | Какой bytes32 проверяется | ABI/source/constant или фактический calldata |
| Admin edge | Кто может изменить роль | getRoleAdmin(targetRole) |
| Membership | Есть ли право у address сейчас | hasRole(role, account) на выбранном block |
- Уровень
- Deployment
- Вопрос
- Какой код исполняется на этом block
- Evidence
- chain ID, address, bytecode и proxy implementation
- Уровень
- Role ID
- Вопрос
- Какой bytes32 проверяется
- Evidence
- ABI/source/constant или фактический calldata
- Уровень
- Admin edge
- Вопрос
- Кто может изменить роль
- Evidence
- getRoleAdmin(targetRole)
- Уровень
- Membership
- Вопрос
- Есть ли право у address сейчас
- Evidence
- hasRole(role, account) на выбранном block
Роль принадлежит deployment на конкретной сети и блоке
Запишите chain ID, contract address, block number/hash и hash runtime bytecode. Если адрес — proxy, определите implementation, активную на этом блоке: вызов идёт в её код, но role state обычно остаётся в storage proxy. Текущий ABI новой implementation нельзя переносить назад без проверки. Для этого сначала нужен разбор proxy, upgrade и admin keys, а затем AccessControl-граф.
Имя роли сначала связывают с точным bytes32
В распространённой реализации role identifier получают как bytes32 constant, часто keccak256 от строки, но само UI-название не гарантирует этот способ или spelling. Возьмите значение из verified source, ABI-accessible getter, deployment artifacts либо декодированного вызова и запишите его полностью. DEFAULT_ADMIN_ROLE в OpenZeppelin AccessControl — отдельная роль со специальной чувствительностью, а не синоним owner любой системы.
Отчёт аудита полезен только если совпадают repository, commit, deployment и implementation. Finding о centralization или role setup не устанавливает текущий on-chain membership без state read; методика проверки scope и remediation остаётся отдельным шагом.
getRoleAdmin строит ребро управления, а не список людей
Для каждой чувствительной role вызовите getRoleAdmin(role). Затем повторите для полученной admin role и проверьте hasRole(adminRole, candidateAccount). В базовом AccessControl DEFAULT_ADMIN_ROLE по умолчанию администрирует и саму себя, поэтому её holder способен grant/revoke другие роли и добавлять новых default admins. Contract может изменить admin relation через внутреннюю настройку, поэтому предположение по названию недопустимо.
| Наблюдение | Что доказывает | Граница |
|---|---|---|
| hasRole=true на block N | Адрес имеет эту role в snapshot N | Не доказывает будущий state или право использовать каждую функцию |
| RoleGranted event | Событие grant было записано | Поздний revoke или upgrade может изменить итог |
| RoleRevoked event | Событие revoke было записано | Нужен receipt success и новый hasRole=false |
| getRoleAdmin=X | Role X управляет target role | Не показывает members X |
| AccessControlEnumerable interface/code | В deployment может быть on-chain enumeration | Базовый AccessControl её не предоставляет |
- Наблюдение
- hasRole=true на block N
- Что доказывает
- Адрес имеет эту role в snapshot N
- Граница
- Не доказывает будущий state или право использовать каждую функцию
- Наблюдение
- RoleGranted event
- Что доказывает
- Событие grant было записано
- Граница
- Поздний revoke или upgrade может изменить итог
- Наблюдение
- RoleRevoked event
- Что доказывает
- Событие revoke было записано
- Граница
- Нужен receipt success и новый hasRole=false
- Наблюдение
- getRoleAdmin=X
- Что доказывает
- Role X управляет target role
- Граница
- Не показывает members X
- Наблюдение
- AccessControlEnumerable interface/code
- Что доказывает
- В deployment может быть on-chain enumeration
- Граница
- Базовый AccessControl её не предоставляет
Полную историю RoleGranted, RoleRevoked и RoleAdminChanged собирают по адресу deployment, с genesis/deployment block до выбранного блока и без обрезанного диапазона RPC. Но итог всегда подтверждают eth_call к hasRole. Правила чтения событий и logs помогают обнаружить пропущенный диапазон, reorg marker или неверный emitter.
Revoke планируют от функции назад к recovery path
Preflight изменения прав
- 1Назовите capability
Перечислите функции, защищённые целевой role, включая pause, mint, upgrade, config и emergency path.
- 2Зафиксируйте graph
Для target role и всех admin roles сохраните bytes32, hasRole, getRoleAdmin, block и implementation.
- 3Найдите независимый путь
Убедитесь, что после revoke остаётся проверенный multisig/timelock/admin, способный выполнить recovery без отзываемого аккаунта.
- 4Симулируйте exact call
Проверьте from, to, calldata, chain, nonce и expected post-state. eth_call не гарантирует включение, но ловит часть ошибок.
- 5Исполните и подтвердите
После successful receipt перечитайте hasRole и admin graph на новом confirmed block.
grantRole и revokeRole доступны только аккаунту, имеющему admin role целевой роли в стандартной реализации. renounceRole предназначен для отказа вызывающего аккаунта и в Contracts 5.x требует caller confirmation; он не является способом произвольно убрать чужого holder. AccessControlDefaultAdminRules, если deployment действительно его использует, добавляет одного default admin и двухшаговую задержанную передачу — эту модель нельзя приписывать обычному AccessControl.
Потерянный admin не восстанавливается универсальной транзакцией
Stop-сигналы
- role ID вычислен из подписи в интерфейсе без сверки source или calldata;
- membership выводят только из events либо из неполного диапазона logs;
- proxy implementation и block context не закреплены;
- предлагается revoke последнего действующего admin без отдельного recovery path;
- eth_call или симуляцию называют гарантией успешного будущего включения;
- для проверки публичного state просят seed, private key или blind signature.
Если ни один доступный account не имеет требуемую admin role, OpenZeppelin AccessControl не содержит скрытого off-chain override. Возможность восстановления должна следовать из другого реально существующего механизма deployment: proxy upgrade authority, timelock, модуль governance или custom emergency function. Перед подписью такого действия проверяйте фактические байты и адрес назначения, а не обещание оператора.
Источники
Мы используем прямые ссылки и фиксируем дату проверки. Полный текст чужих материалов не перепечатывается.
- OpenZeppelin Contracts 5.x — Access Control OpenZeppelin · Проверено 23 августа 2026 г. в 20:06 GMT+5
- OpenZeppelin Contracts 5.x API — Access OpenZeppelin · Проверено 23 августа 2026 г. в 20:06 GMT+5
- OpenZeppelin Upgrades — Proxy Pattern OpenZeppelin · Проверено 23 августа 2026 г. в 20:06 GMT+5
- Ethereum.org — JSON-RPC API ethereum.org · Проверено 23 августа 2026 г. в 20:06 GMT+5
