Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
proposal 1
  • Loading branch information
RenanSouza2 committed Apr 8, 2023
commit 3b8610f90457d877e96a6ce31d53de88aa1b8bee
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes {
// Make sure we keep track of the original numerator in contracts upgraded from a version without checkpoints.
if (oldQuorumNumerator != 0 && _quorumNumeratorHistory._checkpoints.length == 0) {
_quorumNumeratorHistory._checkpoints.push(
Checkpoints.Checkpoint({_blockNumber: 0, _value: SafeCast.toUint224(oldQuorumNumerator)})
Checkpoints.Checkpoint224({_key: 0, _value: SafeCast.toUint224(oldQuorumNumerator)})
);
}

// Set new quorum for future proposals
_quorumNumeratorHistory.push(newQuorumNumerator);
_quorumNumeratorHistory.push(SafeCast.toUint224(newQuorumNumerator));

emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator);
}
Expand Down
32 changes: 32 additions & 0 deletions contracts/utils/Checkpoints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,38 @@ import "./math/SafeCast.sol";
* _Available since v4.5._
*/
library Checkpoints {
/**
* @dev Returns checkpoint at given position.
*/
function getAtPosition(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
return self._checkpoints[pos];
}

/**
* @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.
*
* Returns previous value and new value.
*/
function push(Trace224 storage self, uint256 value) internal returns (uint256, uint256) {
return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value));
}

/**
* @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will
* be set to `op(latest, delta)`.
*
* Returns previous value and new value.
*/
function push(
Trace224 storage self,
function(uint256, uint256) view returns (uint256) op,
uint256 delta
) internal returns (uint256, uint256) {
uint32 key = SafeCast.toUint32(block.number);
uint224 value = SafeCast.toUint224(op(latest(self), delta));
return push(self, key, value);
}

struct Trace224 {
Checkpoint224[] _checkpoints;
}
Expand Down
59 changes: 7 additions & 52 deletions scripts/generate/templates/Checkpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,53 +65,10 @@ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k
`;

const legacyOperations = opts => `\
/**
* @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
* before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
* block, the requested block number must be in the past, excluding the current block.
*/
function getAtBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) {
require(blockNumber < block.number, "Checkpoints: block not yet mined");
uint32 key = SafeCast.toUint32(blockNumber);

uint256 len = self.${opts.checkpointFieldName}.length;
uint256 pos = _upperBinaryLookup(self.${opts.checkpointFieldName}, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName};
}

/**
* @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
* before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched
* checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of
* checkpoints.
*/
function getAtProbablyRecentBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) {
require(blockNumber < block.number, "Checkpoints: block not yet mined");
uint32 key = SafeCast.toUint32(blockNumber);

uint256 len = self.${opts.checkpointFieldName}.length;

uint256 low = 0;
uint256 high = len;

if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self.${opts.checkpointFieldName}, mid)._blockNumber) {
high = mid;
} else {
low = mid + 1;
}
}

uint256 pos = _upperBinaryLookup(self.${opts.checkpointFieldName}, key, low, high);

return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName};
}

/**
* @dev Returns checkpoint at given position.
*/
function getAtPosition(History storage self, uint32 pos) internal view returns (Checkpoint memory) {
function getAtPosition(${opts.historyTypeName} storage self, uint32 pos) internal view returns (${opts.checkpointTypeName} memory) {
return self._checkpoints[pos];
}

Expand All @@ -135,7 +92,9 @@ function push(
function(uint256, uint256) view returns (uint256) op,
uint256 delta
) internal returns (uint256, uint256) {
return push(self, op(latest(self), delta));
uint32 key = SafeCast.toUint32(block.number);
${opts.valueTypeName} value = SafeCast.to${opts.valueTypeNameCap}(op(latest(self), delta));
return push(self, key, value);
}
`;

Expand Down Expand Up @@ -278,23 +237,19 @@ const defaultOpts = size => ({
keyTypeName: `uint${256 - size}`,
keyFieldName: '_key',
valueTypeName: `uint${size}`,
valueTypeNameCap: `Uint${size}`,
valueFieldName: '_value',
});

const OPTS = VALUE_SIZES.map(size => defaultOpts(size));

const LEGACY_OPTS = {
...defaultOpts(224),
historyTypeName: 'History',
checkpointTypeName: 'Checkpoint',
keyFieldName: '_blockNumber',
};

// GENERATE
module.exports = format(
header.trimEnd(),
'library Checkpoints {',
[
// Legacy function
legacyOperations(defaultOpts(224)),
// New flavors
...OPTS.flatMap(opts => [types(opts), operations(opts), common(opts)]),
],
Expand Down