Skip to content
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

Extend Checkpoints with new sizes and lookup mechanisms #3589

Merged
merged 53 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4176852
move mock
Amxx Jul 28, 2022
63edb74
Expand Checkpoint library
Amxx Jul 28, 2022
da0ea31
rename upperLookupExpEnd → upperLookupRecent
Amxx Jul 28, 2022
ed81388
sanity check when pushing checkpoints
Amxx Jul 28, 2022
b91832d
Skip redundant optimisation in VotesQuorumFraction
Amxx Jul 29, 2022
d2a829c
Merge branch 'master' into feature/checkpoint
Amxx Jul 29, 2022
2a6adb3
reset previous history lookup algorithm and reenable quorum checks
Amxx Jul 29, 2022
28f6e6f
Use unsafeAccess to save gas
Amxx Jul 29, 2022
b7e2f64
Merge branch 'master' into feature/checkpoint
Amxx Jul 29, 2022
616c51b
Regenerate contracts
Amxx Jul 29, 2022
3fb185b
Add changelog entry
Amxx Jul 29, 2022
ce0c7a6
use StorageSlot for unsafeAccess returns
Amxx Jul 29, 2022
33741e7
minor rewrite for readability
Amxx Jul 29, 2022
8425e4a
fix typo
Amxx Jul 29, 2022
74fef95
testing unsafeAccess
Amxx Jul 29, 2022
df3a9b1
fix lint
Amxx Jul 29, 2022
e182730
Update CHANGELOG.md
Amxx Jul 29, 2022
9b1f559
Merge branch 'master' into feature/checkpoint
Amxx Aug 14, 2022
768a681
Apply suggestions from code review
Amxx Aug 17, 2022
8d9b177
Update Arrays.sol
Amxx Aug 17, 2022
8dc9d4f
Run prettier as part of the procedural generation
Amxx Aug 17, 2022
4e6aa05
Reactor checkpoints to keep legacy types
Amxx Aug 17, 2022
fffde15
add a comment about files being procedurally generated
Amxx Aug 17, 2022
ac5466a
add extensions for the comments
Amxx Aug 17, 2022
a9a69cf
lint
Amxx Aug 17, 2022
4654237
shorter message
Amxx Aug 17, 2022
b486b6b
Merge branch 'master' into feature/checkpoint
Amxx Aug 25, 2022
2848c3a
regenerate & codespell
Amxx Aug 25, 2022
4c6c65e
update generation script path resolution
Amxx Aug 25, 2022
068513c
address comment from PR
Amxx Aug 26, 2022
bf12a2b
add more neatspec
Amxx Aug 26, 2022
b1d5a09
add more neatspec
Amxx Aug 26, 2022
543d516
Apply suggestions from code review
Amxx Aug 26, 2022
634e279
regenerate
Amxx Aug 26, 2022
17e1ec7
don't insert newline when no previous version is recorded
Amxx Aug 26, 2022
d1af38d
improve checkpoint opts generation
Amxx Aug 26, 2022
253e12a
codespell
Amxx Aug 26, 2022
1ccff75
test coverage
Amxx Aug 26, 2022
4d1d3da
grammar
frangio Aug 29, 2022
2d03e54
improve tests
Amxx Aug 30, 2022
69ac69e
Merge remote-tracking branch 'amxx/feature/checkpoint' into feature/c…
Amxx Aug 30, 2022
5661e71
Update test/utils/Checkpoints.test.js
Amxx Aug 30, 2022
6cd42ce
Apply suggestions from code review
Amxx Aug 30, 2022
9c84034
fix generation
Amxx Aug 30, 2022
b878b23
Update scripts/generate/templates/Checkpoints.js
Amxx Aug 30, 2022
c832e53
Update scripts/generate/templates/Checkpoints.js
Amxx Aug 30, 2022
a450545
Update scripts/generate/templates/Checkpoints.js
Amxx Aug 30, 2022
96122a3
Update scripts/generate/templates/Checkpoints.js
Amxx Aug 30, 2022
c891f58
fix generation
Amxx Aug 30, 2022
47ed78e
add History.getAtRecentBlock & tests
Amxx Aug 30, 2022
533ccef
wording
Amxx Aug 30, 2022
6caea6a
Merge branch 'master' into feature/checkpoint
Amxx Aug 30, 2022
22491c0
wrap docs
frangio Aug 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
* `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580))
* `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600))
* `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use lesser operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640))
* `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589))
* `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589))
* `Array`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589))

### Breaking changes

Expand Down
19 changes: 0 additions & 19 deletions contracts/mocks/ArraysImpl.sol

This file was deleted.

51 changes: 51 additions & 0 deletions contracts/mocks/ArraysMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Arrays.sol";

contract Uint256ArraysMock {
using Arrays for uint256[];

uint256[] private _array;

constructor(uint256[] memory array) {
_array = array;
}

function findUpperBound(uint256 element) external view returns (uint256) {
return _array.findUpperBound(element);
}

function unsafeAccess(uint256 pos) external view returns (uint256) {
return _array.unsafeAccess(pos).value;
}
}

contract AddressArraysMock {
using Arrays for address[];

address[] private _array;

constructor(address[] memory array) {
_array = array;
}

function unsafeAccess(uint256 pos) external view returns (address) {
return _array.unsafeAccess(pos).value;
}
}

contract Bytes32ArraysMock {
using Arrays for bytes32[];

bytes32[] private _array;

constructor(bytes32[] memory array) {
_array = array;
}

function unsafeAccess(uint256 pos) external view returns (bytes32) {
return _array.unsafeAccess(pos).value;
}
}
27 changes: 0 additions & 27 deletions contracts/mocks/CheckpointsImpl.sol

This file was deleted.

92 changes: 92 additions & 0 deletions contracts/mocks/CheckpointsMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/CheckpointsMock.js.

pragma solidity ^0.8.0;

import "../utils/Checkpoints.sol";

contract CheckpointsMock {
using Checkpoints for Checkpoints.History;

Checkpoints.History private _totalCheckpoints;

function latest() public view returns (uint256) {
return _totalCheckpoints.latest();
}

function push(uint256 value) public returns (uint256, uint256) {
return _totalCheckpoints.push(value);
}

function getAtBlock(uint256 blockNumber) public view returns (uint256) {
return _totalCheckpoints.getAtBlock(blockNumber);
}

function getAtRecentBlock(uint256 blockNumber) public view returns (uint256) {
return _totalCheckpoints.getAtRecentBlock(blockNumber);
}

function length() public view returns (uint256) {
return _totalCheckpoints._checkpoints.length;
}
}

contract Checkpoints224Mock {
using Checkpoints for Checkpoints.Trace224;

Checkpoints.Trace224 private _totalCheckpoints;

function latest() public view returns (uint224) {
return _totalCheckpoints.latest();
}

function push(uint32 key, uint224 value) public returns (uint224, uint224) {
return _totalCheckpoints.push(key, value);
}

function lowerLookup(uint32 key) public view returns (uint224) {
return _totalCheckpoints.lowerLookup(key);
}

function upperLookup(uint32 key) public view returns (uint224) {
return _totalCheckpoints.upperLookup(key);
}

function upperLookupRecent(uint32 key) public view returns (uint224) {
return _totalCheckpoints.upperLookupRecent(key);
}

function length() public view returns (uint256) {
return _totalCheckpoints._checkpoints.length;
}
}

contract Checkpoints160Mock {
using Checkpoints for Checkpoints.Trace160;

Checkpoints.Trace160 private _totalCheckpoints;

function latest() public view returns (uint160) {
return _totalCheckpoints.latest();
}

function push(uint96 key, uint160 value) public returns (uint160, uint160) {
return _totalCheckpoints.push(key, value);
}

function lowerLookup(uint96 key) public view returns (uint160) {
return _totalCheckpoints.lowerLookup(key);
}

function upperLookup(uint96 key) public view returns (uint160) {
return _totalCheckpoints.upperLookup(key);
}

function upperLookupRecent(uint96 key) public view returns (uint224) {
return _totalCheckpoints.upperLookupRecent(key);
}

function length() public view returns (uint256) {
return _totalCheckpoints._checkpoints.length;
}
}
1 change: 1 addition & 0 deletions contracts/mocks/EnumerableMapMock.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/EnumerableMapMock.js.

pragma solidity ^0.8.0;

Expand Down
1 change: 1 addition & 0 deletions contracts/mocks/EnumerableSetMock.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/EnumerableSetMock.js.

pragma solidity ^0.8.0;

Expand Down
1 change: 1 addition & 0 deletions contracts/mocks/SafeCastMock.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/SafeCastMock.js.

pragma solidity ^0.8.0;

Expand Down
52 changes: 50 additions & 2 deletions contracts/utils/Arrays.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@

pragma solidity ^0.8.0;

import "./StorageSlot.sol";
import "./math/Math.sol";

/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using StorageSlot for bytes32;

/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
Expand All @@ -31,18 +34,63 @@ library Arrays {

// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds down (it does integer division with truncation).
if (array[mid] > element) {
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}

// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && array[low - 1] == element) {
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}

/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
frangio marked this conversation as resolved.
Show resolved Hide resolved
return slot.getAddressSlot();
}

/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}

/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
}