变量 accountRoles 占用的 slot = 0, slot0里面存储的值也是0. 因此删除 delete accountRoles 并不会删除整个的storage(即把整个的storage置0)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
/// @title RoleAccessControl
/// @dev Library for managing role-based access control.
contract ComplexStorage {
using EnumerableSet for EnumerableSet.Bytes32Set;
bytes32 constant public ROLE_ADMIN = "ADMIN";
bytes32 constant public ROLE_UPGRADE = "UPGRADE";
bytes32 constant public ROLE_CONFIG = "CONFIG";
bytes32 constant public ROLE_KEEPER = "KEEPER";
/// @dev Error thrown when an account does not have the required role.
error InvalidRoleAccess(address account, bytes32 role);
/// @dev Error thrown when an invalid role name is provided.
error InvalidRoleName(bytes32 role);
mapping(address => EnumerableSet.Bytes32Set) accountRoles;
modifier onlyRoleAdmin() {
if (!hasRole(msg.sender, ROLE_ADMIN)) {
revert InvalidRoleAccess(msg.sender, ROLE_ADMIN);
}
_;
}
constructor() {
grantRole(msg.sender, ROLE_ADMIN);
}
/// @dev Checks if the caller has the specified role.
/// @param role The role to check.
function checkRole(bytes32 role) public view {
if (!hasRole(msg.sender, role)) {
revert InvalidRoleAccess(msg.sender, role);
}
}
/// @dev Checks if the caller has the specified role.
/// @param role The role to check.
/// @return True if the caller has the role, false otherwise.
function hasRole(bytes32 role) public view returns (bool) {
return hasRole(msg.sender, role);
}
/// @dev Checks if an account has the specified role.
/// @param account The account to check.
/// @param role The role to check.
/// @return True if the account has the role, false otherwise.
function hasRole(address account, bytes32 role) public view returns (bool) {
return accountRoles[account].contains(role);
}
/// @dev Grants a role to an account. public for test
/// @param account The account to grant the role to.
/// @param role The role to grant.
function grantRole(address account, bytes32 role) public {
accountRoles[account].add(role);
}
/// @dev Revokes a role from an account. public for test
/// @param account The account to revoke the role from.
/// @param role The role to revoke.
function revokeRole(address account, bytes32 role) public {
if (accountRoles[account].contains(role)) {
accountRoles[account].remove(role);
}
}
/// @dev Revokes all roles from an account. public for test
/// @param account The account to revoke all roles from.
function revokeAllRole(address account) public {
delete accountRoles[account];//@audit 问题在这里,这个slot的值本身就是0,比如是slot111222,它只起到计算后面的EnumerableSet.Bytes32Set的slot的作用
}
}
以上面的代码为例:
变量 accountRoles 占用的 slot = 0, slot0里面存储的值也是0.
因此删除 delete accountRoles
并不会删除整个的storage(即把整个的storage置0)
同理:
accountRoles[account] 占用的slot = keccak256(abi.encode(account, 0)) 假设为slotX, slotX里面存储的值也是0.
因此删除 accountRoles[account]
也不会删除 里面 EnumerableSet.Bytes32Set结构体的值。它只是 让 slotX这个slot里面存储值=0,而已。而这个值本身就是0.
slotX的作用是让结构体 来寻址用的 keccak256(abi.encode(Value, slotX)),Value为account或者动态数组的下标如1,2,3
测试代码:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {Test, console2} from "forge-std/Test.sol";
import {ComplexStorage} from "../../src/mapping-storage/ComplexStorage.sol";
contract ComplexStorageTest is Test{
bytes32 constant public ROLE_ADMIN = "ADMIN";
bytes32 constant public ROLE_UPGRADE = "UPGRADE";
bytes32 constant public ROLE_CONFIG = "CONFIG";
bytes32 constant public ROLE_KEEPER = "KEEPER";
address public user1;
ComplexStorage public cs;
function setUp() public {
cs = new ComplexStorage();
user1 = makeAddr("user1");
}
function testHasAdminRole() public{
assertEq(cs.hasRole(ROLE_ADMIN), true);
assertEq(cs.hasRole(ROLE_UPGRADE), false);
}
function testAddAndRemoveRole() public{
cs.grantRole(user1, ROLE_UPGRADE);
cs.grantRole(user1, ROLE_CONFIG);
cs.grantRole(user1, ROLE_KEEPER);
assertEq(true, cs.hasRole(user1, ROLE_UPGRADE));
assertEq(false, cs.hasRole(user1, ROLE_ADMIN));
cs.revokeRole(user1, ROLE_UPGRADE);
//remove role_upgrade
assertEq(true, cs.hasRole(user1, ROLE_KEEPER));
assertEq(false, cs.hasRole(user1, ROLE_UPGRADE));
cs.revokeAllRole(user1);
//nothing change
assertEq(true, cs.hasRole(user1, ROLE_KEEPER));
assertEq(true, cs.hasRole(user1, ROLE_CONFIG));
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!