Skip to content

Commit

Permalink
cherry-pick sorted set validation util from chainlink repo
Browse files Browse the repository at this point in the history
Signed-off-by: 0xsuryansh <[email protected]>
  • Loading branch information
0xsuryansh committed Jul 10, 2024
1 parent 2dfeeca commit 5680cee
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 2 deletions.
17 changes: 15 additions & 2 deletions contracts/gas-snapshots/shared.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas()
CallWithExactGas__callWithExactGas:test_NoContractReverts() (gas: 11559)
CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 15788)
CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 16241)
CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15812, ~: 15752)
CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15811, ~: 15752)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 20116)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 67721)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 256, μ: 16321, ~: 16262)
Expand Down Expand Up @@ -70,4 +70,17 @@ OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649)
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649)
OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957)
OpStackBurnMintERC677_interfaceCompatibility:testStaticFunctionsCompatibility() (gas: 13781)
OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752)
OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySubset_Reverts() (gas: 5460)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySuperset_Reverts() (gas: 4661)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_HasDuplicates_Reverts() (gas: 8265)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_NotASubset_Reverts() (gas: 12487)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubset() (gas: 4489)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_Equal() (gas: 1464)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_NotEqual_Reverts() (gas: 6172)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() (gas: 8867)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() (gas: 16544)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() (gas: 9420)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() (gas: 7380)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() (gas: 9600)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_ValidSubset_Success() (gas: 6490)
168 changes: 168 additions & 0 deletions contracts/src/v0.8/shared/test/util/SortedSetValidationUtil.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {SortedSetValidationUtil} from "../../../shared/util/SortedSetValidationUtil.sol";
import {BaseTest} from "../BaseTest.t.sol";

contract SortedSetValidationUtilBaseTest is BaseTest {
uint256 constant OFFSET = 5;

modifier _ensureSetLength(uint256 subsetLength, uint256 supersetLength) {
vm.assume(subsetLength > 0 && supersetLength > 0 && subsetLength <= supersetLength);
_;
}

function _createSets(
uint256 subsetLength,
uint256 supersetLength
) internal pure returns (bytes32[] memory subset, bytes32[] memory superset) {
subset = new bytes32[](subsetLength);
superset = new bytes32[](supersetLength);
}

function _convertArrayToSortedSet(bytes32[] memory arr, uint256 offSet) internal pure {
for (uint256 i = 1; i < arr.length; ++i) {
arr[i] = bytes32(uint256(arr[i - 1]) + offSet);
}
}

function _convertToUnsortedSet(bytes32[] memory arr, uint256 ptr1, uint256 ptr2) internal pure {
// Swap two elements to make it unsorted
(arr[ptr1], arr[ptr2]) = (arr[ptr2], arr[ptr1]);
}

function _convertArrayToSubset(bytes32[] memory subset, bytes32[] memory superset) internal pure {
for (uint256 i; i < subset.length; ++i) {
subset[i] = superset[i];
}
}

function _makeInvalidSubset(bytes32[] memory subset, bytes32[] memory superset, uint256 ptr) internal pure {
_convertArrayToSubset(subset, superset);
subset[ptr] = bytes32(uint256(subset[ptr]) + 1);
}

function _convertArrayToHaveDuplicates(bytes32[] memory arr, uint256 ptr1, uint256 ptr2) internal pure {
arr[ptr2] = arr[ptr1];
}
}

contract SortedSetValidationUtil_CheckIsValidUniqueSubsetTest is SortedSetValidationUtilBaseTest {
// Successes.

function test__checkIsValidUniqueSubset_ValidSubset_Success() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 5);
_convertArrayToSortedSet(superset, OFFSET);
_convertArrayToSubset(subset, superset);

SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

// Reverts.

function test__checkIsValidUniqueSubset_EmptySubset_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(0, 5);
_convertArrayToSortedSet(superset, OFFSET);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.EmptySet.selector));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_EmptySuperset_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 0);
_convertArrayToSortedSet(subset, OFFSET);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.EmptySet.selector));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_NotASubset_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 5);
_convertArrayToSortedSet(superset, OFFSET);
_makeInvalidSubset(subset, superset, 1);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASubset.selector, subset, superset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 5);
_convertArrayToSortedSet(superset, OFFSET);
_convertToUnsortedSet(subset, 1, 2);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, subset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 5);
_convertArrayToSortedSet(superset, OFFSET);
_convertArrayToSubset(subset, superset);
_convertToUnsortedSet(superset, 1, 2);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, superset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_HasDuplicates_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 5);
_convertArrayToSortedSet(superset, OFFSET);
_convertArrayToSubset(subset, superset);
_convertArrayToHaveDuplicates(subset, 1, 2);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, subset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(6, 5);
_convertArrayToSortedSet(subset, OFFSET);
_convertArrayToSortedSet(superset, OFFSET);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASubset.selector, subset, superset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(5, 5);
_convertArrayToSortedSet(subset, OFFSET);
_convertArrayToSortedSet(superset, OFFSET);

SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_SingleElementSubset() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(1, 5);
_convertArrayToSortedSet(superset, OFFSET);
_convertArrayToSubset(subset, superset);

SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_Equal() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(1, 1);
_convertArrayToSortedSet(subset, OFFSET);
_convertArrayToSortedSet(superset, OFFSET);

SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_NotEqual_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(1, 1);
_convertArrayToSortedSet(subset, OFFSET);
superset[0] = bytes32(uint256(subset[0]) + 10); // Different value

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASubset.selector, subset, superset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}

function test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() public {
(bytes32[] memory subset, bytes32[] memory superset) = _createSets(3, 5);
_convertArrayToSortedSet(superset, OFFSET);
_convertArrayToSubset(subset, superset);
_convertArrayToHaveDuplicates(superset, 1, 2);

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, superset));
SortedSetValidationUtil._checkIsValidUniqueSubset(subset, superset);
}
}
1 change: 1 addition & 0 deletions contracts/src/v0.8/shared/util/SortedSetValidationUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ library SortedSetValidationUtil {
error NotASubset(bytes32[] subset, bytes32[] superset);

/// @notice Checks if `subset` is a valid and unique subset of `superset`.
/// NOTE: Empty set is not considered a valid subset of superset for our use case.
/// @dev Both arrays must be valid sets (unique, sorted in ascending order) and `subset` must be entirely contained within `superset`.
/// @param subset The array of bytes32 to validate as a subset.
/// @param superset The array of bytes32 in which subset is checked against.
Expand Down

0 comments on commit 5680cee

Please sign in to comment.