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

Move Validators.sol to 0.8 #11192

Merged
merged 45 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ff1263f
WIP
martinvol Aug 20, 2024
6290189
Validator test WIP, forge doesn't compile yet
martinvol Aug 20, 2024
9945a58
buildable
pahor167 Aug 21, 2024
88e14d6
most of the foundry tests working
pahor167 Aug 21, 2024
7e49f20
Validator related tests fixed
pahor167 Aug 21, 2024
e07edbd
truffle build working
pahor167 Aug 21, 2024
b5622b1
cache bump
pahor167 Aug 21, 2024
d57297f
lint + prettify+ migrations
pahor167 Aug 21, 2024
55cb6cb
Enable optimization for Solidity 0.8
pahor167 Aug 21, 2024
2b06798
prettify
pahor167 Aug 21, 2024
47b3529
Ci bump
pahor167 Aug 21, 2024
8efa5b2
CI bump 2
pahor167 Aug 21, 2024
9ba9e31
Validators to 0.8 config
pahor167 Aug 21, 2024
dcc2553
CI bump
pahor167 Aug 21, 2024
b71f9ec
Merge branch 'feat/l2-epoch-system' into martinvol/validators0.8
pahor167 Aug 21, 2024
f5f3651
foundry fix
pahor167 Aug 21, 2024
f703c3f
Truffle migrations are partly fixed
pahor167 Aug 21, 2024
fa102f2
Merge branch 'martinvol/validators0.8' of https://github.com/celo-org…
pahor167 Aug 21, 2024
b1f2605
Added import for ValidatorsMock08 in EpochManager.t.sol, I think it w…
martinvol Aug 21, 2024
ab45833
Added yarn.lock
martinvol Aug 21, 2024
9fdfe14
Changes to mock with full implementation
martinvol Aug 21, 2024
9418531
Attempt to fix linking libraries not working with deployCodeTo https:…
martinvol Aug 22, 2024
7df0417
truffle migrations fixed
pahor167 Aug 22, 2024
95ff956
CI bump
pahor167 Aug 22, 2024
a79283b
lint
pahor167 Aug 22, 2024
2a71465
forge test fixes
pahor167 Aug 22, 2024
c3ce03e
artifacts test fix
pahor167 Aug 22, 2024
bbba961
lint
pahor167 Aug 22, 2024
9a09a3b
update of foundry version
pahor167 Aug 22, 2024
af268ba
add ProxyFactory import to tests
pahor167 Aug 22, 2024
dc056be
library linking fix
pahor167 Aug 22, 2024
451559e
Foundry migrations fix
pahor167 Aug 22, 2024
82bff43
migration tests fix
pahor167 Aug 22, 2024
baa09ec
CI bump
pahor167 Aug 22, 2024
8eed51d
Little cleanup + retrigger CI
martinvol Aug 22, 2024
21a97c7
forgot to commit Validators.sol
martinvol Aug 22, 2024
fac5545
Fixed the ABI encoded
martinvol Aug 23, 2024
080e530
lint
martinvol Aug 23, 2024
b8576b7
Fix contract versions
martinvol Aug 23, 2024
eb5ba95
add Adapter to ignored contracts
pahor167 Aug 26, 2024
134a6fc
revert of ReentrancyGuard change
pahor167 Aug 26, 2024
f07a560
Merge branch 'feat/l2-epoch-system' into martinvol/validators0.8
pahor167 Aug 26, 2024
4dd9bf6
lint fix
pahor167 Aug 26, 2024
4d245d6
remove adapters from check
pahor167 Aug 26, 2024
7adb03a
storage layout fix
pahor167 Aug 26, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/celo-monorepo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ defaults:

env:
# Increment these to force cache rebuilding
NODE_MODULE_CACHE_VERSION: 7
NODE_MODULE_CACHE_VERSION: 8
NODE_OPTIONS: '--max-old-space-size=4096'
TERM: dumb
GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.parallel=false -Dorg.gradle.configureondemand=true -Dorg.gradle.jvmargs="-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError"'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/protocol-devchain-anvil.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: ${{ env.SUPPORTED_FOUNDRY_VERSION }}
version: 'nightly-fa0e0c2ca3ae75895dd19173a02faf88509c0608'

- name: Install forge dependencies
run: forge install
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/protocol_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: ${{ env.SUPPORTED_FOUNDRY_VERSION }}
version: 'nightly-fa0e0c2ca3ae75895dd19173a02faf88509c0608'

- name: Install forge dependencies
run: forge install
Expand Down Expand Up @@ -153,4 +153,4 @@ jobs:

FOUNDRY_PROFILE=devchain forge test -vvv \
--match-path "test-sol/devchain/e2e/*" \
--fork-url $ANVIL_RPC_URL
--fork-url $ANVIL_RPC_URL
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@
path = packages/protocol/lib/celo-foundry
url = https://github.com/celo-org/celo-foundry
branch = celo-foundry-v0.5.13
[submodule "packages/protocol/lib/solidity-bytes-utils-8"]
path = packages/protocol/lib/solidity-bytes-utils-8
url = https://github.com/GNSPS/solidity-bytes-utils
branch = master
3 changes: 2 additions & 1 deletion packages/protocol/contractPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ export const SOLIDITY_08_PACKAGE = {
proxiesPath: '/', // Proxies are still with 0.5 contracts
// Proxies shouldn't have to be added to a list manually
// https://github.com/celo-org/celo-monorepo/issues/10555
contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'CeloUnreleasedTreasure'],
contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'CeloUnreleasedTreasure', 'Validators'],
proxyContracts: [
'GasPriceMinimumProxy',
'FeeCurrencyDirectoryProxy',
'MentoFeeCurrencyAdapterV1',
'CeloUnreleasedTreasureProxy',
'ValidatorsProxy',
],
truffleConfig: 'truffle-config0.8.js',
} satisfies ContractPackage
166 changes: 159 additions & 7 deletions packages/protocol/contracts-0.8/common/UsingPrecompiles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,39 @@ contract UsingPrecompiles is IsL2Check {
address constant GET_VERIFIED_SEAL_BITMAP = address(0xff - 11);
uint256 constant DAY = 86400;

/**
* @notice calculate a * b^x for fractions a, b to `decimals` precision
* @param aNumerator Numerator of first fraction
* @param aDenominator Denominator of first fraction
* @param bNumerator Numerator of exponentiated fraction
* @param bDenominator Denominator of exponentiated fraction
* @param exponent exponent to raise b to
* @param _decimals precision
* @return Numerator of the computed quantity (not reduced).
* @return Denominator of the computed quantity (not reduced).
*/
function fractionMulExp(
uint256 aNumerator,
uint256 aDenominator,
uint256 bNumerator,
uint256 bDenominator,
uint256 exponent,
uint256 _decimals
) public view returns (uint256, uint256) {
require(aDenominator != 0 && bDenominator != 0, "a denominator is zero");
uint256 returnNumerator;
uint256 returnDenominator;
bool success;
bytes memory out;
(success, out) = FRACTION_MUL.staticcall(
abi.encodePacked(aNumerator, aDenominator, bNumerator, bDenominator, exponent, _decimals)
);
require(success, "error calling fractionMulExp precompile");
returnNumerator = getUint256FromBytes(out, 0);
returnDenominator = getUint256FromBytes(out, 32);
return (returnNumerator, returnDenominator);
}

/**
* @notice Returns the current epoch size in blocks.
* @return The current epoch size in blocks.
Expand Down Expand Up @@ -54,6 +87,36 @@ contract UsingPrecompiles is IsL2Check {
return getEpochNumberOfBlock(block.number);
}

/**
* @notice Gets a validator address from the current validator set.
* @param index Index of requested validator in the validator set.
* @return Address of validator at the requested index.
*/
function validatorSignerAddressFromCurrentSet(uint256 index) public view returns (address) {
bytes memory out;
bool success;
(success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number)));
require(success, "error calling validatorSignerAddressFromCurrentSet precompile");
return address(uint160(getUint256FromBytes(out, 0)));
}

/**
* @notice Gets a validator address from the validator set at the given block number.
* @param index Index of requested validator in the validator set.
* @param blockNumber Block number to retrieve the validator set from.
* @return Address of validator at the requested index.
*/
function validatorSignerAddressFromSet(
uint256 index,
uint256 blockNumber
) public view returns (address) {
bytes memory out;
bool success;
(success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, blockNumber));
require(success, "error calling validatorSignerAddressFromSet precompile");
return address(uint160(getUint256FromBytes(out, 0)));
}

/**
* @notice Gets the size of the current elected validator set.
* @return Size of the current elected validator set.
Expand All @@ -67,16 +130,105 @@ contract UsingPrecompiles is IsL2Check {
}

/**
* @notice Gets a validator address from the current validator set.
* @param index Index of requested validator in the validator set.
* @return Address of validator at the requested index.
* @notice Gets the size of the validator set that must sign the given block number.
* @param blockNumber Block number to retrieve the validator set from.
* @return Size of the validator set.
*/
function validatorSignerAddressFromCurrentSet(uint256 index) public view returns (address) {
function numberValidatorsInSet(uint256 blockNumber) public view returns (uint256) {
bytes memory out;
bool success;
(success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number)));
require(success, "error calling validatorSignerAddressFromCurrentSet precompile");
return address(uint160(getUint256FromBytes(out, 0)));
(success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(blockNumber));
require(success, "error calling numberValidatorsInSet precompile");
return getUint256FromBytes(out, 0);
}

/**
* @notice Checks a BLS proof of possession.
* @param sender The address signed by the BLS key to generate the proof of possession.
* @param blsKey The BLS public key that the validator is using for consensus, should pass proof
* of possession. 48 bytes.
* @param blsPop The BLS public key proof-of-possession, which consists of a signature on the
* account address. 96 bytes.
* @return True upon success.
*/
function checkProofOfPossession(
address sender,
bytes memory blsKey,
bytes memory blsPop
) public view returns (bool) {
bool success;
(success, ) = PROOF_OF_POSSESSION.staticcall(abi.encodePacked(sender, blsKey, blsPop));
return success;
}

/**
* @notice Parses block number out of header.
* @param header RLP encoded header
* @return Block number.
*/
function getBlockNumberFromHeader(bytes memory header) public view returns (uint256) {
bytes memory out;
bool success;
(success, out) = BLOCK_NUMBER_FROM_HEADER.staticcall(abi.encodePacked(header));
require(success, "error calling getBlockNumberFromHeader precompile");
return getUint256FromBytes(out, 0);
}

/**
* @notice Computes hash of header.
* @param header RLP encoded header
* @return Header hash.
*/
function hashHeader(bytes memory header) public view returns (bytes32) {
bytes memory out;
bool success;
(success, out) = HASH_HEADER.staticcall(abi.encodePacked(header));
require(success, "error calling hashHeader precompile");
return getBytes32FromBytes(out, 0);
}

/**
* @notice Gets the parent seal bitmap from the header at the given block number.
* @param blockNumber Block number to retrieve. Must be within 4 epochs of the current number.
* @return Bitmap parent seal with set bits at indices corresponding to signing validators.
*/
function getParentSealBitmap(uint256 blockNumber) public view returns (bytes32) {
bytes memory out;
bool success;
(success, out) = GET_PARENT_SEAL_BITMAP.staticcall(abi.encodePacked(blockNumber));
require(success, "error calling getParentSealBitmap precompile");
return getBytes32FromBytes(out, 0);
}

/**
* @notice Verifies the BLS signature on the header and returns the seal bitmap.
* The validator set used for verification is retrieved based on the parent hash field of the
* header. If the parent hash is not in the blockchain, verification fails.
* @param header RLP encoded header
* @return Bitmap parent seal with set bits at indices correspoinding to signing validators.
*/
function getVerifiedSealBitmapFromHeader(bytes memory header) public view returns (bytes32) {
bytes memory out;
bool success;
(success, out) = GET_VERIFIED_SEAL_BITMAP.staticcall(abi.encodePacked(header));
require(success, "error calling getVerifiedSealBitmapFromHeader precompile");
return getBytes32FromBytes(out, 0);
}

/**
* @notice Returns the minimum number of required signers for a given block number.
* @dev Computed in celo-blockchain as int(math.Ceil(float64(2*valSet.Size()) / 3))
*/
function minQuorumSize(uint256 blockNumber) public view returns (uint256) {
return numberValidatorsInSet(blockNumber).mul(2).add(2).div(3);
}

/**
* @notice Computes byzantine quorum from current validator set size
* @return Byzantine quorum of validators.
*/
function minQuorumSizeInCurrentSet() public view returns (uint256) {
return minQuorumSize(block.number);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.13 <0.9.0;

interface IPrecompiles {
function getEpochSize() external view returns (uint256);
function getEpochNumber() external view returns (uint256);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
pragma solidity >=0.8.0 <0.8.20;

import "@openzeppelin/contracts8/utils/math/SafeMath.sol";

import "./LinkedList.sol";

/**
* @title Maintains a doubly linked list keyed by address.
* @dev Following the `next` pointers will lead you to the head, rather than the tail.
*/
library AddressLinkedList {
using LinkedList for LinkedList.List;
using SafeMath for uint256;
/**
* @notice Inserts an element into a doubly linked list.
* @param list A storage pointer to the underlying list.
* @param key The key of the element to insert.
* @param previousKey The key of the element that comes before the element to insert.
* @param nextKey The key of the element that comes after the element to insert.
*/
function insert(
LinkedList.List storage list,
address key,
address previousKey,
address nextKey
) public {
list.insert(toBytes(key), toBytes(previousKey), toBytes(nextKey));
}

/**
* @notice Inserts an element at the end of the doubly linked list.
* @param list A storage pointer to the underlying list.
* @param key The key of the element to insert.
*/
function push(LinkedList.List storage list, address key) public {
list.insert(toBytes(key), bytes32(0), list.tail);
}

/**
* @notice Removes an element from the doubly linked list.
* @param list A storage pointer to the underlying list.
* @param key The key of the element to remove.
*/
function remove(LinkedList.List storage list, address key) public {
list.remove(toBytes(key));
}

/**
* @notice Updates an element in the list.
* @param list A storage pointer to the underlying list.
* @param key The element key.
* @param previousKey The key of the element that comes before the updated element.
* @param nextKey The key of the element that comes after the updated element.
*/
function update(
LinkedList.List storage list,
address key,
address previousKey,
address nextKey
) public {
list.update(toBytes(key), toBytes(previousKey), toBytes(nextKey));
}

/**
* @notice Returns whether or not a particular key is present in the sorted list.
* @param list A storage pointer to the underlying list.
* @param key The element key.
* @return Whether or not the key is in the sorted list.
*/
function contains(LinkedList.List storage list, address key) public view returns (bool) {
return list.elements[toBytes(key)].exists;
}

/**
* @notice Returns the N greatest elements of the list.
* @param list A storage pointer to the underlying list.
* @param n The number of elements to return.
* @return The keys of the greatest elements.
* @dev Reverts if n is greater than the number of elements in the list.
*/
function headN(LinkedList.List storage list, uint256 n) public view returns (address[] memory) {
bytes32[] memory byteKeys = list.headN(n);
address[] memory keys = new address[](n);
for (uint256 i = 0; i < n; i = i.add(1)) {
keys[i] = toAddress(byteKeys[i]);
}
return keys;
}

/**
* @notice Gets all element keys from the doubly linked list.
* @param list A storage pointer to the underlying list.
* @return All element keys from head to tail.
*/
function getKeys(LinkedList.List storage list) public view returns (address[] memory) {
return headN(list, list.numElements);
}

function toBytes(address a) public pure returns (bytes32) {
return bytes32(uint256(uint160(a)) << 96);
}

function toAddress(bytes32 b) public pure returns (address) {
return address(uint160(uint256(b) >> 96));
}
}
Loading
Loading