Explorar el Código

Add getRoleMembers method to return all accounts that have role (#4546)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Ernesto García <ernestognw@gmail.com>
Vladimir Khramov hace 1 año
padre
commit
ef68ac3ed8

+ 5 - 0
.changeset/violet-moons-tell.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`AccessControlEnumerable`: Add a `getRoleMembers` method to return all accounts that have `role`.

+ 12 - 0
contracts/access/extensions/AccessControlEnumerable.sol

@@ -46,6 +46,18 @@ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessCon
         return _roleMembers[role].length();
     }
 
+    /**
+     * @dev Return all accounts that have `role`
+     *
+     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
+     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
+     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
+     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
+     */
+    function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
+        return _roleMembers[role].values();
+    }
+
     /**
      * @dev Overload {AccessControl-_grantRole} to track enumerable memberships
      */

+ 7 - 5
test/access/AccessControl.behavior.js

@@ -239,15 +239,17 @@ function shouldBehaveLikeAccessControlEnumerable() {
       await this.mock.connect(this.defaultAdmin).grantRole(ROLE, this.otherAuthorized);
       await this.mock.connect(this.defaultAdmin).revokeRole(ROLE, this.other);
 
-      const memberCount = await this.mock.getRoleMemberCount(ROLE);
-      expect(memberCount).to.equal(2);
+      const expectedMembers = [this.authorized.address, this.otherAuthorized.address];
 
-      const bearers = [];
+      const memberCount = await this.mock.getRoleMemberCount(ROLE);
+      const members = [];
       for (let i = 0; i < memberCount; ++i) {
-        bearers.push(await this.mock.getRoleMember(ROLE, i));
+        members.push(await this.mock.getRoleMember(ROLE, i));
       }
 
-      expect(bearers).to.have.members([this.authorized.address, this.otherAuthorized.address]);
+      expect(memberCount).to.equal(expectedMembers.length);
+      expect(members).to.deep.equal(expectedMembers);
+      expect(await this.mock.getRoleMembers(ROLE)).to.deep.equal(expectedMembers);
     });
 
     it('role enumeration should be in sync after renounceRole call', async function () {