-
Notifications
You must be signed in to change notification settings - Fork 4
feat: switch to mapping instead of linear search #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,12 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| /// @notice Mapping to quickly check if an address is an active recipient | ||
| /// @dev Maps recipient address to true if active, false otherwise | ||
| mapping(address => bool) isRecipientMapping; | ||
| /// @notice Mapping to quickly check if an address is queued for addition | ||
| /// @dev Maps recipient address to true if queued for addition, false otherwise | ||
| mapping(address => bool) isQueuedForAdditionMapping; | ||
| /// @notice Mapping to quickly check if an address is queued for removal | ||
| /// @dev Maps recipient address to true if queued for removal, false otherwise | ||
| mapping(address => bool) isQueuedForRemovalMapping; | ||
| } | ||
|
|
||
| // keccak256(abi.encode(uint256(keccak256("crowdstake.storage.AbstractRecipientRegistry")) - 1)) & ~bytes32(uint256(0xff)) | ||
|
|
@@ -89,14 +95,9 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| AbstractRecipientRegistryStorage storage $ = _getAbstractRecipientRegistryStorage(); | ||
| if (recipient == address(0)) revert InvalidRecipient(); | ||
| if ($.isRecipientMapping[recipient]) revert RecipientAlreadyExists(); | ||
| if ($.isQueuedForAdditionMapping[recipient]) revert RecipientAlreadyQueued(); | ||
|
|
||
| // Check if already queued to prevent duplicates | ||
| for (uint256 i = 0; i < $.queuedRecipientsForAddition.length; i++) { | ||
| if ($.queuedRecipientsForAddition[i] == recipient) { | ||
| revert RecipientAlreadyQueued(); | ||
| } | ||
| } | ||
|
|
||
| $.isQueuedForAdditionMapping[recipient] = true; | ||
| $.queuedRecipientsForAddition.push(recipient); | ||
| emit RecipientQueued(recipient, true); | ||
| } | ||
|
|
@@ -109,15 +110,11 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| /// @dev Access control should be implemented in the calling public function | ||
| function _queueForRemoval(address recipient) internal { | ||
| AbstractRecipientRegistryStorage storage $ = _getAbstractRecipientRegistryStorage(); | ||
| if (recipient == address(0)) revert InvalidRecipient(); | ||
| if (!$.isRecipientMapping[recipient]) revert RecipientNotFound(); | ||
| if ($.isQueuedForRemovalMapping[recipient]) revert RecipientAlreadyQueued(); | ||
|
|
||
| // Check if already queued for removal to prevent duplicates | ||
| for (uint256 i = 0; i < $.queuedRecipientsForRemoval.length; i++) { | ||
| if ($.queuedRecipientsForRemoval[i] == recipient) { | ||
| revert RecipientAlreadyQueued(); | ||
| } | ||
| } | ||
|
|
||
| $.isQueuedForRemovalMapping[recipient] = true; | ||
| $.queuedRecipientsForRemoval.push(recipient); | ||
| emit RecipientQueued(recipient, false); | ||
| } | ||
|
|
@@ -144,6 +141,7 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| address recipient = addedList[i]; | ||
| $.recipients.push(recipient); | ||
| $.isRecipientMapping[recipient] = true; | ||
| $.isQueuedForAdditionMapping[recipient] = false; | ||
| emit RecipientAdded(recipient); | ||
| } | ||
|
|
||
|
|
@@ -161,6 +159,7 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| if (recipient == removedList[j]) { | ||
| shouldRemove = true; | ||
| $.isRecipientMapping[recipient] = false; | ||
| $.isQueuedForRemovalMapping[recipient] = false; | ||
| emit RecipientRemoved(recipient); | ||
| break; | ||
| } | ||
|
|
@@ -184,14 +183,22 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| /// @dev Only owner can clear the queue. Use this to cancel all pending additions | ||
| /// @dev This will remove all addresses from the addition queue without adding them | ||
| function clearAdditionQueue() external onlyOwner { | ||
| delete _getAbstractRecipientRegistryStorage().queuedRecipientsForAddition; | ||
| AbstractRecipientRegistryStorage storage $ = _getAbstractRecipientRegistryStorage(); | ||
| for (uint256 i = 0; i < $.queuedRecipientsForAddition.length; i++) { | ||
| $.isQueuedForAdditionMapping[$.queuedRecipientsForAddition[i]] = false; | ||
| } | ||
| delete $.queuedRecipientsForAddition; | ||
|
Comment on lines
+191
to
+195
|
||
| } | ||
|
|
||
| /// @notice Clear the removal queue without processing | ||
| /// @dev Only owner can clear the queue. Use this to cancel all pending removals | ||
| /// @dev This will remove all addresses from the removal queue without removing them | ||
| function clearRemovalQueue() external onlyOwner { | ||
| delete _getAbstractRecipientRegistryStorage().queuedRecipientsForRemoval; | ||
| AbstractRecipientRegistryStorage storage $ = _getAbstractRecipientRegistryStorage(); | ||
| for (uint256 i = 0; i < $.queuedRecipientsForRemoval.length; i++) { | ||
| $.isQueuedForRemovalMapping[$.queuedRecipientsForRemoval[i]] = false; | ||
| } | ||
| delete $.queuedRecipientsForRemoval; | ||
|
Comment on lines
+202
to
+206
|
||
| } | ||
|
|
||
| /// @notice Get all active recipients | ||
|
|
@@ -226,26 +233,14 @@ abstract contract AbstractRecipientRegistry is IRecipientRegistry, OwnableUpgrad | |
| /// @param recipient Address to check in the addition queue | ||
| /// @return isQueued True if the address is queued for addition, false otherwise | ||
| function isQueuedForAddition(address recipient) external view returns (bool isQueued) { | ||
| AbstractRecipientRegistryStorage storage $ = _getAbstractRecipientRegistryStorage(); | ||
| for (uint256 i = 0; i < $.queuedRecipientsForAddition.length; i++) { | ||
| if ($.queuedRecipientsForAddition[i] == recipient) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| return _getAbstractRecipientRegistryStorage().isQueuedForAdditionMapping[recipient]; | ||
| } | ||
|
|
||
| /// @notice Check if an address is queued for removal | ||
| /// @param recipient Address to check in the removal queue | ||
| /// @return isQueued True if the address is queued for removal, false otherwise | ||
| function isQueuedForRemoval(address recipient) external view returns (bool isQueued) { | ||
| AbstractRecipientRegistryStorage storage $ = _getAbstractRecipientRegistryStorage(); | ||
| for (uint256 i = 0; i < $.queuedRecipientsForRemoval.length; i++) { | ||
| if ($.queuedRecipientsForRemoval[i] == recipient) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| return _getAbstractRecipientRegistryStorage().isQueuedForRemovalMapping[recipient]; | ||
| } | ||
|
|
||
| /// @notice Check if an address is currently an active recipient | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR description references solving #45 (duplicate checks for both addition and removal queues), but this change only adds an O(1) check for the addition queue. The removal queue still uses a linear scan, so large removal queues will keep the same O(n) behavior. Either extend the mapping approach to removals as well, or adjust the PR/issue linkage to reflect the remaining work.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
b39b223