Parcourir la source

Refactor Governor proposal struct for efficient access (#4495)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Vladislav Volosnikov il y a 2 ans
Parent
commit
54a235f895
1 fichiers modifiés avec 21 ajouts et 30 suppressions
  1. 21 30
      contracts/governance/Governor.sol

+ 21 - 30
contracts/governance/Governor.sol

@@ -40,22 +40,13 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
         uint32 voteDuration;
         bool executed;
         bool canceled;
-    }
-
-    struct ProposalExtra {
         uint48 eta;
     }
 
-    // Each object in this should fit into a single slot so it can be cached efficiently
-    struct ProposalFull {
-        ProposalCore core;
-        ProposalExtra extra;
-    }
-
     bytes32 private constant _ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1);
     string private _name;
 
-    mapping(uint256 => ProposalFull) private _proposals;
+    mapping(uint256 => ProposalCore) private _proposals;
 
     // This queue keeps track of the governor operating on itself. Calls to functions protected by the
     // {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute},
@@ -144,13 +135,16 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
      * @dev See {IGovernor-state}.
      */
     function state(uint256 proposalId) public view virtual override returns (ProposalState) {
-        // ProposalCore is just one slot. We can load it from storage to memory with a single sload and use memory
-        // object as a cache. This avoid duplicating expensive sloads.
-        ProposalCore memory core = _proposals[proposalId].core;
+        // ProposalCore is just one slot. We can load it from storage to stack with a single sload
+        ProposalCore storage proposal = _proposals[proposalId];
+        bool proposalExecuted = proposal.executed;
+        bool proposalCanceled = proposal.canceled;
 
-        if (core.executed) {
+        if (proposalExecuted) {
             return ProposalState.Executed;
-        } else if (core.canceled) {
+        }
+
+        if (proposalCanceled) {
             return ProposalState.Canceled;
         }
 
@@ -190,28 +184,28 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
      * @dev See {IGovernor-proposalSnapshot}.
      */
     function proposalSnapshot(uint256 proposalId) public view virtual override returns (uint256) {
-        return _proposals[proposalId].core.voteStart;
+        return _proposals[proposalId].voteStart;
     }
 
     /**
      * @dev See {IGovernor-proposalDeadline}.
      */
     function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) {
-        return _proposals[proposalId].core.voteStart + _proposals[proposalId].core.voteDuration;
+        return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration;
     }
 
     /**
      * @dev See {IGovernor-proposalProposer}.
      */
     function proposalProposer(uint256 proposalId) public view virtual override returns (address) {
-        return _proposals[proposalId].core.proposer;
+        return _proposals[proposalId].proposer;
     }
 
     /**
      * @dev See {IGovernor-proposalEta}.
      */
     function proposalEta(uint256 proposalId) public view virtual override returns (uint256) {
-        return _proposals[proposalId].extra.eta;
+        return _proposals[proposalId].eta;
     }
 
     /**
@@ -311,20 +305,17 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
         if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) {
             revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length);
         }
-        if (_proposals[proposalId].core.voteStart != 0) {
+        if (_proposals[proposalId].voteStart != 0) {
             revert GovernorUnexpectedProposalState(proposalId, state(proposalId), bytes32(0));
         }
 
         uint256 snapshot = clock() + votingDelay();
         uint256 duration = votingPeriod();
 
-        _proposals[proposalId].core = ProposalCore({
-            proposer: proposer,
-            voteStart: SafeCast.toUint48(snapshot),
-            voteDuration: SafeCast.toUint32(duration),
-            executed: false,
-            canceled: false
-        });
+        ProposalCore storage proposal = _proposals[proposalId];
+        proposal.proposer = proposer;
+        proposal.voteStart = SafeCast.toUint48(snapshot);
+        proposal.voteDuration = SafeCast.toUint32(duration);
 
         emit ProposalCreated(
             proposalId,
@@ -357,7 +348,7 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
         uint48 eta = _queueOperations(proposalId, targets, values, calldatas, descriptionHash);
 
         if (eta != 0) {
-            _proposals[proposalId].extra.eta = eta;
+            _proposals[proposalId].eta = eta;
             emit ProposalQueued(proposalId, eta);
         } else {
             revert GovernorQueueNotImplemented();
@@ -406,7 +397,7 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
         );
 
         // mark as executed before calls to avoid reentrancy
-        _proposals[proposalId].core.executed = true;
+        _proposals[proposalId].executed = true;
 
         // before execute: register governance call in queue.
         if (_executor() != address(this)) {
@@ -494,7 +485,7 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72
                 _encodeStateBitmap(ProposalState.Executed)
         );
 
-        _proposals[proposalId].core.canceled = true;
+        _proposals[proposalId].canceled = true;
         emit ProposalCanceled(proposalId);
 
         return proposalId;