-
Notifications
You must be signed in to change notification settings - Fork 55
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
V2 optimize #55
Merged
Merged
V2 optimize #55
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
c9f3072
Optimize RegistryHashes library
Vectorized 3032921
Add branchless operations
Vectorized adf0d4b
Optimize RegistryStorage
Vectorized 6a9cb05
Gas benchmarks
Vectorized 8f34062
Use back branching && in _validateDelegation
Vectorized 8f792be
Gas benchmarks
Vectorized cafa302
Add memory-safe tags
Vectorized 2160282
Optimize hashes a bit more
Vectorized c6852b0
Nit comment
Vectorized 2120c03
Minor optimizations
Vectorized becd414
Merge branch 'v2' into v2-optimize
0xfoobar 9cf1dbd
Minor optimizations
Vectorized 21d7dbd
Merge branch 'v2-optimize' of https://github.com/Vectorized/delegate-…
Vectorized 765da84
Minor optimizations
Vectorized ce3b4b0
Gas benchmarks
Vectorized 89f755c
Merge branch 'v2' into v2-optimize
0xfoobar d357baf
Nit typo
Vectorized a9dc73a
Fixes
Vectorized 3562ecd
Add comments for max function
Vectorized 5ac544d
Add truthyness demostrations
Vectorized 243f76d
Add more truthyness demostrations
Vectorized 21cc5de
Fix
Vectorized 47c114e
Fix
Vectorized 67cef7d
Gas benchmark
Vectorized 6e25a49
fmt
Vectorized 1ff5448
Optimize Ops
Vectorized File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ pragma solidity ^0.8.21; | |
import {IDelegateRegistry as IDelegateRegistry} from "./IDelegateRegistry.sol"; | ||
import {RegistryHashes as Hashes} from "./libraries/RegistryHashes.sol"; | ||
import {RegistryStorage as Storage} from "./libraries/RegistryStorage.sol"; | ||
import {RegistryOps as Ops} from "./libraries/RegistryOps.sol"; | ||
|
||
/** | ||
* @title DelegateRegistry | ||
|
@@ -133,25 +134,37 @@ contract DelegateRegistry is IDelegateRegistry { | |
/// @inheritdoc IDelegateRegistry | ||
function checkDelegateForAll(address to, address from, bytes32 rights) external view override returns (bool valid) { | ||
valid = _validateDelegation(Hashes.allLocation(from, "", to), from); | ||
if (rights != "" && !valid) valid = _validateDelegation(Hashes.allLocation(from, rights, to), from); | ||
if (!Ops.or(rights == "", valid)) valid = _validateDelegation(Hashes.allLocation(from, rights, to), from); | ||
assembly ("memory-safe") { | ||
mstore(0x00, iszero(iszero(valid))) | ||
return(0x00, 0x20) // Direct return. Skips Solidity's redundant copying to save gas. | ||
} | ||
} | ||
|
||
/// @inheritdoc IDelegateRegistry | ||
function checkDelegateForContract(address to, address from, address contract_, bytes32 rights) external view override returns (bool valid) { | ||
valid = _validateDelegation(Hashes.allLocation(from, "", to), from) || _validateDelegation(Hashes.contractLocation(from, "", to, contract_), from); | ||
if (rights != "" && !valid) { | ||
if (!Ops.or(rights == "", valid)) { | ||
valid = _validateDelegation(Hashes.allLocation(from, rights, to), from) || _validateDelegation(Hashes.contractLocation(from, rights, to, contract_), from); | ||
} | ||
assembly ("memory-safe") { | ||
mstore(0x00, iszero(iszero(valid))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. |
||
return(0x00, 0x20) // Direct return. Skips Solidity's redundant copying to save gas. | ||
} | ||
} | ||
|
||
/// @inheritdoc IDelegateRegistry | ||
function checkDelegateForERC721(address to, address from, address contract_, uint256 tokenId, bytes32 rights) external view override returns (bool valid) { | ||
valid = _validateDelegation(Hashes.allLocation(from, "", to), from) || _validateDelegation(Hashes.contractLocation(from, "", to, contract_), from) | ||
|| _validateDelegation(Hashes.erc721Location(from, "", to, tokenId, contract_), from); | ||
if (rights != "" && !valid) { | ||
if (!Ops.or(rights == "", valid)) { | ||
valid = _validateDelegation(Hashes.allLocation(from, rights, to), from) || _validateDelegation(Hashes.contractLocation(from, rights, to, contract_), from) | ||
|| _validateDelegation(Hashes.erc721Location(from, rights, to, tokenId, contract_), from); | ||
} | ||
assembly ("memory-safe") { | ||
mstore(0x00, iszero(iszero(valid))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. |
||
return(0x00, 0x20) // Direct return. Skips Solidity's redundant copying to save gas. | ||
} | ||
} | ||
|
||
/// @inheritdoc IDelegateRegistry | ||
|
@@ -160,12 +173,16 @@ contract DelegateRegistry is IDelegateRegistry { | |
amount = (_validateDelegation(Hashes.allLocation(from, "", to), from) || _validateDelegation(Hashes.contractLocation(from, "", to, contract_), from)) | ||
? type(uint256).max | ||
: (_validateDelegation(location, from) ? _loadDelegationUint(location, Storage.Positions.amount) : 0); | ||
if (rights != "" && amount != type(uint256).max) { | ||
if (!Ops.or(rights == "", amount == type(uint256).max)) { | ||
location = Hashes.erc20Location(from, rights, to, contract_); | ||
uint256 rightsBalance = ( | ||
_validateDelegation(Hashes.allLocation(from, rights, to), from) || _validateDelegation(Hashes.contractLocation(from, rights, to, contract_), from) | ||
) ? type(uint256).max : (_validateDelegation(location, from) ? _loadDelegationUint(location, Storage.Positions.amount) : 0); | ||
amount = rightsBalance > amount ? rightsBalance : amount; | ||
amount = Ops.max(rightsBalance, amount); | ||
} | ||
assembly ("memory-safe") { | ||
mstore(0x00, amount) | ||
return(0x00, 0x20) // Direct return. Skips Solidity's redundant copying to save gas. | ||
} | ||
} | ||
|
||
|
@@ -175,12 +192,16 @@ contract DelegateRegistry is IDelegateRegistry { | |
amount = (_validateDelegation(Hashes.allLocation(from, "", to), from) || _validateDelegation(Hashes.contractLocation(from, "", to, contract_), from)) | ||
? type(uint256).max | ||
: (_validateDelegation(location, from) ? _loadDelegationUint(location, Storage.Positions.amount) : 0); | ||
if (rights != "" && amount != type(uint256).max) { | ||
if (!Ops.or(rights == "", amount == type(uint256).max)) { | ||
location = Hashes.erc1155Location(from, rights, to, tokenId, contract_); | ||
uint256 rightsBalance = ( | ||
_validateDelegation(Hashes.allLocation(from, rights, to), from) || _validateDelegation(Hashes.contractLocation(from, rights, to, contract_), from) | ||
) ? type(uint256).max : (_validateDelegation(location, from) ? _loadDelegationUint(location, Storage.Positions.amount) : 0); | ||
amount = rightsBalance > amount ? rightsBalance : amount; | ||
amount = Ops.max(rightsBalance, amount); | ||
} | ||
assembly ("memory-safe") { | ||
mstore(0x00, amount) | ||
return(0x00, 0x20) // Direct return. Skips Solidity's redundant copying to save gas. | ||
} | ||
} | ||
|
||
|
@@ -215,7 +236,7 @@ contract DelegateRegistry is IDelegateRegistry { | |
for (uint256 i = 0; i < hashes.length; ++i) { | ||
bytes32 location = Hashes.location(hashes[i]); | ||
address from = _loadFrom(location, Storage.Positions.firstPacked); | ||
if (from == DELEGATION_EMPTY || from == DELEGATION_REVOKED) { | ||
if (Ops.or(from == DELEGATION_EMPTY, from == DELEGATION_REVOKED)) { | ||
delegations_[i] = Delegation({type_: DelegationType.NONE, to: address(0), from: address(0), rights: "", amount: 0, contract_: address(0), tokenId: 0}); | ||
} else { | ||
(, address to, address contract_) = _loadDelegationAddresses(location, Storage.Positions.firstPacked, Storage.Positions.secondPacked); | ||
|
@@ -259,7 +280,7 @@ contract DelegateRegistry is IDelegateRegistry { | |
/// @param interfaceId The interface identifier | ||
/// @return valid Whether the queried interface is supported | ||
function supportsInterface(bytes4 interfaceId) external pure returns (bool) { | ||
return interfaceId == type(IDelegateRegistry).interfaceId || interfaceId == 0x01ffc9a7; | ||
return Ops.or(interfaceId == type(IDelegateRegistry).interfaceId, interfaceId == 0x01ffc9a7); | ||
} | ||
|
||
/** | ||
|
@@ -384,7 +405,12 @@ contract DelegateRegistry is IDelegateRegistry { | |
} | ||
|
||
/// @dev Helper function to establish whether a delegation is enabled | ||
function _validateDelegation(bytes32 location, address from) internal view returns (bool) { | ||
return (_loadFrom(location, Storage.Positions.firstPacked) == from && from > DELEGATION_REVOKED); | ||
function _validateDelegation(bytes32 location, address from) internal view returns (bool result) { | ||
uint256 loaded = uint256(uint160(_loadFrom(location, Storage.Positions.firstPacked))); | ||
uint256 revoked = uint256(uint160(DELEGATION_REVOKED)); | ||
uint256 fromCasted = uint256(uint160(from)); | ||
assembly { | ||
result := and(eq(fromCasted, loaded), gt(fromCasted, revoked)) | ||
} | ||
mireynolds marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This still assumes
valid
is free of dirty bits, which the compiler doesn't guarantee. Avalid
with dirty bits will incorrectly return false underiszero
even if the last 8 bits are set to zero. If we're going to use assembly here, we need to cleanvalid
, then store it in memory for return. Compiler will do this under the hood, so if we want to skip a bit of gas on the return we need to ensure it's going to give the same result as if there were no assembly block overriding the return ofvalid
.