访问 - OpenZeppelin 文档

本文档介绍了OpenZeppelin Contracts库中用于访问控制的组件,包括Ownable、AccessControl和TimelockController。Ownable提供简单的所有者权限控制,AccessControl提供更细粒度的基于角色的访问控制,而TimelockController则在访问控制中引入时间锁机制,确保关键操作执行前有足够的时间让用户做出反应。

你当前阅读的不是此文档的最新版本。5.x 是当前版本。

访问控制

https://docs.openzeppelin.com/contracts/api/access 处查看此文档效果更佳

此目录提供了限制谁可以访问合约功能或何时可以访问的方式。

  • AccessControl 提供了一种通用的基于角色的访问控制机制。可以创建多个分层角色,并将每个角色分配给多个帐户。

  • Ownable 是一种更简单的机制,具有一个可以分配给单个帐户的单个所有者“角色”。这种更简单的机制对于快速测试很有用,但具有生产问题的项目可能会超越它。

  • TimelockController 与上述两种机制之一结合使用。通过将角色分配给 TimelockController 合约的实例,对该角色控制的功能的访问将被延迟一段时间。

授权

Ownable

合约模块,提供基本的访问控制机制,其中 存在一个帐户(所有者),可以被授予对 特定功能的独占访问权。

默认情况下,所有者帐户将是部署合约的帐户。这 可以稍后使用 transferOwnership 更改。

此模块通过继承使用。它将提供修饰符 onlyOwner,可以将其应用于你的函数以将它们的使用限制为 所有者。

修饰符

函数

事件

onlyOwner() 修饰符

如果由所有者以外的任何帐户调用,则抛出异常。

constructor() 内部函数

初始化合约,将部署者设置为初始所有者。

owner() → address public

返回当前所有者的地址。

renounceOwnership() public

使合约没有所有者。将无法再调用 onlyOwner 函数。只能由当前所有者调用。

放弃所有权将使合约没有所有者,<br>从而删除任何仅对所有者可用的功能。
transferOwnership(address newOwner) public

将合约的所有权转移到新帐户(newOwner)。 只能由当前所有者调用。

OwnershipTransferred(address previousOwner, address newOwner) 事件

AccessControl

合约模块,允许子合约实现基于角色的访问 控制机制。

角色由其 bytes32 标识符引用。这些应该在 外部 API 中公开并且是唯一的。实现此目的的最佳方法是 使用 public constant 哈希摘要:

bytes32 public constant MY_ROLE = keccak256("MY_ROLE");

角色可用于表示一组权限。要限制对 函数调用的访问,请使用 hasRole

function foo() public {
    require(hasRole(MY_ROLE, msg.sender));
    ...
}

角色可以通过 grantRolerevokeRole 函数动态地授予和撤销。每个角色都有一个关联的管理角色,并且只有 具有角色管理角色的帐户才能调用 grantRolerevokeRole

默认情况下,所有角色的管理角色都是 DEFAULT_ADMIN_ROLE,这意味着 只有具有此角色的帐户才能授予或撤销其他 角色。可以通过使用 _setRoleAdmin 创建更复杂的角色关系。

DEFAULT_ADMIN_ROLE 也是它自己的管理员:它有权<br>授予和撤销此角色。应采取额外的预防措施来保护<br>已被授予它的帐户。

函数

事件

hasRole(bytes32 role, address account) → bool public

如果 account 已被授予 role,则返回 true

getRoleMemberCount(bytes32 role) → uint256 public

返回拥有 role 的帐户数量。可以与 getRoleMember 一起使用来枚举角色的所有持有者。

getRoleMember(bytes32 role, uint256 index) → address public

返回拥有 role 的帐户之一。index 必须是 0 和 getRoleMemberCount 之间的值,不包括在内。

角色持有者不以任何特定方式排序,并且它们的排序可能 在任何时候更改。

当使用 getRoleMembergetRoleMemberCount 时,请确保<br>在同一区块上执行所有查询。请参阅以下<br>论坛帖子<br>以获取更多信息。
getRoleAdmin(bytes32 role) → bytes32 public

返回控制 role 的管理角色。请参阅 grantRolerevokeRole

要更改角色的管理员,请使用 _setRoleAdmin

grantRole(bytes32 role, address account) public

role 授予 account

如果 account 尚未被授予 role,则发出 RoleGranted 事件。

要求:

  • 调用者必须具有 role 的管理角色。
revokeRole(bytes32 role, address account) public

account 撤销 role

如果 account 已被授予 role,则发出 RoleRevoked 事件。

要求:

  • 调用者必须具有 role 的管理角色。
renounceRole(bytes32 role, address account) public

从调用帐户撤销 role

角色通常通过 grantRolerevokeRole 管理:此函数 旨在提供一种机制,使帐户在 受到威胁时(例如,当可信设备放错地方时)失去其权限。

如果调用帐户已被授予 role,则发出 RoleRevoked 事件。

要求:

  • 调用者必须是 account
_setupRole(bytes32 role, address account) internal

role 授予 account

如果 account 尚未被授予 role,则发出 RoleGranted 事件。请注意,与 grantRole 不同,此函数不会对 调用帐户执行任何检查。

仅应在设置<br>系统的初始角色时从构造函数中调用此函数。<br>以任何其他方式使用此函数实际上是在规避由 AccessControl 施加的管理<br>系统。
_setRoleAdmin(bytes32 role, bytes32 adminRole) internal

adminRole 设置为 role 的管理角色。

发出 RoleAdminChanged 事件。

RoleAdminChanged(bytes32 role, bytes32 previousAdminRole, bytes32 newAdminRole) event

newAdminRole 设置为 role 的管理角色时发出,替换 previousAdminRole

DEFAULT_ADMIN_ROLE 是所有角色的起始管理员,尽管 RoleAdminChanged 未发出信号表明这一点。

自 v3.1 起可用。

RoleGranted(bytes32 role, address account, address sender) event

account 被授予 role 时发出。

sender 是发起合约调用的帐户,是管理角色 持有者,除非使用 _setupRole

RoleRevoked(bytes32 role, address account, address sender) event

account 被撤销 role 时发出。

sender 是发起合约调用的帐户:

  • 如果使用 revokeRole,则是管理角色持有者
  • 如果使用 renounceRole,则是角色持有者(即 account

时间锁

TimelockController

合约模块,充当时间锁定的控制器。当设置为 Ownable 智能合约的所有者时,它会对所有 onlyOwner 维护操作强制执行时间锁。这使受控合约的用户有时间在应用潜在危险的维护 操作之前退出。

默认情况下,此合约是自我管理的,这意味着管理任务 必须经过时间锁过程。提议者(resp 执行者)角色 负责提议(resp 执行)操作。一个常见的用例是 将此 TimelockController 定位为智能合约的所有者, 多重签名或 DAO 作为唯一提议者。

自 v3.3 起可用。

修饰符

函数

AccessControl

事件

AccessControl

onlyRole(bytes32 role) 修饰符

修饰符,使函数只能由特定角色调用。除了 检查发送者的角色外,还考虑了 address(0) 的角色。将角色授予 address(0) 等同于为所有人启用 此角色。

constructor(uint256 minDelay, address[] proposers, address[] executors) public

使用给定的 minDelay 初始化合约。

receive() external

合约可能会接收/持有 ETH 作为维护过程的一部分。

isOperation(bytes32 id) → bool pending public

返回 id 是否对应于已注册的操作。这 包括挂起、准备就绪和完成的操作。

isOperationPending(bytes32 id) → bool pending public

返回操作是否挂起。

isOperationReady(bytes32 id) → bool ready public

返回操作是否准备就绪。

isOperationDone(bytes32 id) → bool done public

返回操作是否已完成。

getTimestamp(bytes32 id) → uint256 timestamp public

返回操作准备就绪的时间戳(未设置的操作为 0, 完成的操作为 1)。

getMinDelay() → uint256 duration public

返回操作变为有效所需的最小延迟。

可以通过执行调用 updateDelay 的操作来更改此值。

hashOperation(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt) → bytes32 hash public

返回包含单个 事务的操作的标识符。

hashOperationBatch(address[] targets, uint256[] values, bytes[] datas, bytes32 predecessor, bytes32 salt) → bytes32 hash public

返回包含一批 事务的操作的标识符。

schedule(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt, uint256 delay) public

计划包含单个事务的操作。

发出 CallScheduled 事件。

要求:

  • 调用者必须具有“提议者”角色。
scheduleBatch(address[] targets, uint256[] values, bytes[] datas, bytes32 predecessor, bytes32 salt, uint256 delay) public

计划包含一批事务的操作。

为批处理中的每个事务发出一个 CallScheduled 事件。

要求:

  • 调用者必须具有“提议者”角色。
cancel(bytes32 id) public

取消操作。

要求:

  • 调用者必须具有“提议者”角色。
execute(address target, uint256 value, bytes data, bytes32 predecessor, bytes32 salt) public

执行包含单个事务的(就绪)操作。

发出 CallExecuted 事件。

要求:

  • 调用者必须具有“执行者”角色。
executeBatch(address[] targets, uint256[] values, bytes[] datas, bytes32 predecessor, bytes32 salt) public

执行包含一批事务的(就绪)操作。

为批处理中的每个事务发出一个 CallExecuted 事件。

要求:

  • 调用者必须具有“执行者”角色。
updateDelay(uint256 newDelay) external

更改未来操作的最小时间锁持续时间。

发出 MinDelayChange 事件。

要求:

  • 调用者必须是时间锁本身。这只能通过计划并在以后执行 时间锁是目标的操作,并且数据是对此函数的 ABI 编码调用来实现。
CallScheduled(bytes32 id, uint256 index, address target, uint256 value, bytes data, bytes32 predecessor, uint256 delay) event

当调用计划为操作 id 的一部分时发出。

CallExecuted(bytes32 id, uint256 index, address target, uint256 value, bytes data) event

当调用作为操作 id 的一部分执行时发出。

Cancelled(bytes32 id) event

当操作 id 被取消时发出。

MinDelayChange(uint256 oldDuration, uint256 newDuration) event

当未来操作的最小延迟被修改时发出。

术语
  • 操作: 作为时间锁主题的事务(或一组事务)。它必须由提议者计划并由执行者执行。时间锁强制执行提议和执行之间的最短延迟(请参阅操作生命周期)。如果操作包含多个事务(批处理模式),则它们以原子方式执行。通过操作内容的哈希值来标识操作。

  • 操作状态:

  • 未设置: 不属于时间锁机制的操作。

  • 挂起: 已计划但计时器尚未到期的操作。

  • 准备就绪: 已计划且计时器已到期的操作。

  • 完成: 已执行的操作。

  • 前置: 操作之间的(可选)依赖关系。一个操作可以依赖于另一个操作(其前置操作),从而强制执行这两个操作的执行顺序。

  • 角色:

  • 提议者: 负责计划(和取消)操作的地址(智能合约或 EOA)。

  • 执行者: 负责执行提议者计划的操作的地址(智能合约或 EOA)。

操作结构

TimelockControler 执行的操作可以包含一个或多个后续调用。根据是否需要原子方式执行多个调用,可以使用简单操作或批处理操作。

两种操作都包含:

  • 目标,时间锁应操作的智能合约的地址。

  • ,以 wei 为单位,应随事务一起发送。大多数情况下,这将为 0。以太币可以在执行事务之前或执行事务时沿途存入或传递。

  • 数据,包含调用的编码函数选择器和参数。这可以使用多种工具生成。例如,使用 web3js 可以按如下方式编码将角色 ROLE 授予 ACCOUNT 的维护操作:

const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
  • 前置,指定操作之间的依赖关系。此依赖关系是可选的。如果操作没有任何依赖关系,请使用 bytes32(0)

  • ,用于消除两个其他相同的操作的歧义。这可以是任何随机值。

在批处理操作的情况下,targetvaluedata 被指定为数组,这些数组的长度必须相同。

操作生命周期

时间锁操作由唯一的 id(它们的哈希值)标识,并遵循特定的生命周期:

UnsetPendingPending + ReadyDone

  • 通过调用 schedule(或 scheduleBatch),提议者将操作从 Unset 状态移动到 Pending 状态。这将启动一个计时器,该计时器必须长于最小延迟。计时器在可以通过 getTimestamp 方法访问的时间戳到期。

  • 计时器到期后,操作会自动进入 Ready 状态。此时,可以执行它。

  • 通过调用 execute(或 executeBatch),执行者触发操作的基础事务并将其移动到 Done 状态。如果操作具有前置操作,则该前置操作必须处于 Done 状态才能使此转换成功。

  • cancel 允许提议者取消任何 Pending 操作。这将操作重置为 Unset 状态。因此,提议者可以重新计划已取消的操作。在这种情况下,当重新计划操作时,计时器会重新启动。

可以使用以下函数查询操作状态:

角色
管理员

管理员负责管理提议者和执行者。为了使时间锁能够自我管理,此角色应仅授予时间锁本身。部署后,时间锁和部署者都具有此角色。在进一步配置和测试之后,部署者可以放弃此角色,以便所有进一步的维护操作都必须通过时间锁过程。

此角色由 TIMELOCK_ADMIN_ROLE 值标识:0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5

提议者

提议者负责计划(和取消)操作。这是一个关键角色,应授予治理实体。这可以是 EOA、多重签名或 DAO。

提议者之争: 拥有多个提议者虽然可以在一个提议者不可用时提供冗余,但这可能很危险。由于提议者对所有操作都有发言权,他们可以取消他们不同意的操作,包括删除他们的提议者操作。

此角色由 PROPOSER_ROLE 值标识:0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1

执行者

执行者负责在时间锁到期后执行提议者计划的操作。从逻辑上讲,作为提议者的多重签名或 DAO 也应该是执行者,以保证已计划的操作最终会被执行。但是,拥有额外的执行者可以降低成本(执行事务不需要提出它的多重签名或 DAO 的验证),同时确保负责执行的任何人都不能触发未由提议者计划的操作。

此角色由 EXECUTOR_ROLE 值标识:0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63

没有至少一个提议者和一个执行者的实时合约将被锁定。在部署者放弃其有利于时间锁合约本身的行政权利之前,请确保这些角色由可靠的实体担任。请参阅AccessControl 文档以了解有关角色管理的更多信息。

← 实用工具

密码学 →

  • 原文链接: docs.openzeppelin.com/co...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。