Openzeppelin学习记录一:access模块(AccessControl.sol+Ownable.sol)

Posted 一袋芋头

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Openzeppelin学习记录一:access模块(AccessControl.sol+Ownable.sol)相关的知识,希望对你有一定的参考价值。

Openzeppelin学习记录

Openzeppelin学习记录

OpenZeppelin的智能合约代码库是以太坊开发者的宝库,OpenZeppelin代码库包含了经过社区审查的ERC代币标准、安全协议以及很多的辅助工具库,这些代码可以帮助开发者专注业务逻辑的,而无需重新发明轮子。

基于OpenZeppelin开发合约,即可以提高代码的安全性,又可以提高开发效率。(这两段话抄的登链社区哈哈哈)

本文只记录学习过程中的的一些想法和问题,目前没有实操。

本人英文文档阅读能力有限,这也是第一次尝试阅读英文文档(之前都是看的中文版,但这次搜到的都太老了,solidity还在用0.4+的版本~),如有错误欢迎大家批评指正!

模块结构

github上下下来原始合约,目录结构如图所示:

-contracts
	-access//主要包含拥有者管理和角色管理
		AccessControl.sol				//角色管理,1对1
        AccessControlEnumerable.sol		//角色管理,1对多
        Ownable.sol						//拥有者管理
     -finance  
     -governance 
     -interfaces
     -metax
     -mocks
     -proxys
     -security
     -token
     -utils

今天先写一下access部分的笔记

1. access

1.1 AccessControl.sol

该文件为角色管理合约:其中有两个关键角色:role和roleAdmin

合约中提供了几个函数来进行角色的转换,其中包括一些查询函数,此外还有角色转变函数,和角色改变时会触发的event.

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool);//(没太懂)
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role));
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role));
function renounceRole(bytes32 role, address account) public virtual override;
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual;

其中,

admin:
	grantRole
	revokeRole

role:
	renounonceRole
	
更改admin的函数(可见性是internal的,应该是在使用者自己的合约中调用)
_setRoleAdmin

具体文件如下(害怕出错,英文注释没有动,添加了一些自己理解的中文注释)

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl 
    function hasRole(bytes32 role, address account) external view returns (bool);

    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    function grantRole(bytes32 role, address account) external;

    function revokeRole(bytes32 role, address account) external;

    function renounceRole(bytes32 role, address account) external;


/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * AccessControlEnumerable.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use hasRole:
 *
 * ```
 * function foo() public 
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * 
 * ```
 *
 * Roles can be granted and revoked dynamically via the grantRole and
 * revokeRole functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call grantRole and revokeRole.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * _setRoleAdmin.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 
    struct RoleData 
        mapping(address => bool) members;
        bytes32 adminRole;
    

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * RoleAdminChanged not being emitted signaling this.
     *
     * _Available since v3.1._
     */
     //更改角色role管理员(0x00是所有角色的初始管理员,尽管刚开始的时候没有发出这个事件)
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using _setupRole.
     */
     //sender(通常是admin)授予某accounte为role
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
     //sender(通常是admin)撤销某accounte的role
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]20) is missing role (0x[0-9a-f]32)$/
     *
     * _Available since v4.1._
     */
     //检查调用者是否有某角色(没有进行一些处理(回复消息告知其不是该角色))
    modifier onlyRole(bytes32 role) 
        _checkRole(role, _msgSender());
        _;
    

    /**
     * @dev See IERC165-supportsInterface.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) 
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
        //当使用super时,调用的是继承的该函数,不是它自己
    

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) 
        return _roles[role].members[account];
    

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]20) is missing role (0x[0-9a-f]32)$/
     */
    function _checkRole(bytes32 role, address account) internal view 
        if (!hasRole(role, account)) 
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        
    

    /**
     * @dev Returns the admin role that controls `role`. See grantRole and
     * revokeRole.
     *
     * To change a role's admin, use _setRoleAdmin.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) 
        return _roles[role].adminRole;
    

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a RoleGranted
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
     //msg.sender= admin,授予account 的role
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) 
        _grantRole(role, account);
    

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a RoleRevoked event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
     //admin撤销account 的role
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) 
        _revokeRole(role, account);
    

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via grantRole and revokeRole: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a RoleRevoked
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
     //account 主动撤销自己的角色
    function renounceRole(bytes32 role, address account) public virtual override 
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a RoleGranted
     * event. Note that unlike grantRole, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by AccessControl.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual 
        _grantRole(role, account);
    

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a RoleAdminChanged event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual 
        emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
        _roles[role].adminRole = adminRole;
    

    function _grantRole(bytes32 role, address account) private 
        if (!hasRole(role, account)) 
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        
    

    function _revokeRole(bytes32 role, address account) private 
        if (hasRole(role, account)) 
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        
    


1.2 AccessControlEnumerable.sol

1.1 是一对一,这个是一对多,就是管理一个同为role的集合roles,大体功能是一样的,我没仔细看,把代码贴这吧

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable 
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    function getRoleMemberCount(bytes32 role) external view returns (uint256);


/**
 * @dev Extension of AccessControl that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl 
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See IERC165-supportsInterface.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) 
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and getRoleMemberCount, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using getRoleMember and getRoleMemberCount, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view override returns (address) 
        return _roleMembers[role].at(index);
    

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with getRoleMember to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view override returns (uint256) 
        return _roleMembers[role].length();
    

    /**
     * @dev Overload grantRole to track enumerable memberships
     */
    function grantRole(bytes32 role, address account) public virtual override 
        super.grantRole(role, account);
        _roleMembers[role].add(account);
    

    /**
     * @dev Overload revokeRole to track enumerable memberships
     */
    function revokeRole(bytes32 role, address account) public virtual override 
        super.revokeRole(role, account);
        _roleMembers[role].remove(account);
    

    /**
     * @dev Overload renounceRole to track enumerable memberships
     */
    function renounceRole(bytes32 role, address account) public virtual override 
        super.renounceRole(role, account);
        _roleMembers[role].remove(account);
    

    /**
     * @dev Overload _setupRole to track enumerable memberships
     */
    function _setupRole(bytes32 role, address account) internal virtual override 
        super._setupRole(role, account);
        _roleMembers[role].add(account);
    


1.3 Ownable.sol

该合约用的最多了,给所部署的合约设置一个拥有者,一次来约束合约中和某些操作的权限。可以称得上典中典!

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with transferOwnership.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.

 *默认情况下,所有者帐户将是部署合约的帐户。这以后可以用 transferOwnership 更改。
 *该模块通过继承使用。它将使修饰符可用`onlyOwner`,可以应用于您的函数以限制它们的使用者。
 */
 
abstract contract Ownable is Context 
    address private _owner;
    //拥有者身份转移
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
     //初始化合约,将部署者设置为初始所有者
    constructor() 
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) 
        return _owner;
    

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() 
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */

     //使合约没有所有者。将无法调用`onlyOwner` 不再起作用。只能由当前所有者调用。
    // 注意:放弃所有权将使合约没有所有者,从而删除任何仅对所有者可用的功能
    function renounceOwnership() public virtual onlyOwner 
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
     //原拥有者将权力交接给新人(青天已死,黄天当立)
    function transferOwnership(address newOwner) public virtual onlyOwner 
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    


OK,access看完啦!

以上是关于Openzeppelin学习记录一:access模块(AccessControl.sol+Ownable.sol)的主要内容,如果未能解决你的问题,请参考以下文章

Openzeppelin学习记录一:access模块(AccessControl.sol+Ownable.sol)

Openzeppelin学习记录一:access模块(AccessControl.sol+Ownable.sol)

Openzeppelin学习记录二:utils模块(SafeMath.sol+SafeCast.sol)

Openzeppelin学习记录二:utils模块(SafeMath.sol+SafeCast.sol)

Openzeppelin学习记录二:utils模块(SafeMath.sol+SafeCast.sol)

Openzeppelin学习记录二:utils模块(SafeMath.sol+SafeCast.sol)