Skip to content

Commit

Permalink
feat(Gear.exe): impl initial election logic (#4362)
Browse files Browse the repository at this point in the history
  • Loading branch information
grishasobol authored Dec 3, 2024
1 parent 91f8496 commit 427e6d3
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 55 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
[submodule "ethexe/contracts/lib/forge-std"]
path = ethexe/contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = "v1"
[submodule "ethexe/contracts/lib/openzeppelin-contracts"]
path = ethexe/contracts/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
branch = "release-v5.1"
[submodule "ethexe/contracts/lib/openzeppelin-foundry-upgrades"]
path = ethexe/contracts/lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
branch = "main"
[submodule "ethexe/contracts/lib/openzeppelin-contracts-upgradeable"]
path = ethexe/contracts/lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
branch = "release-v5.1"
[submodule "ethexe/contracts/lib/symbiotic-core"]
path = ethexe/contracts/lib/symbiotic-core
url = https://github.com/grishasobol/symbiotic-core
4 changes: 2 additions & 2 deletions ethexe/contracts/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"editor.defaultFormatter": "JuanBlanco.solidity"
},
"solidity.formatter": "forge",
"solidity.compileUsingRemoteVersion": "v0.8.25"
}
"solidity.compileUsingRemoteVersion": "v0.8.28"
}
2 changes: 2 additions & 0 deletions ethexe/contracts/foundry.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[profile.default]
solc_version = "0.8.28"
src = "src"
out = "out"
libs = ["lib"]
Expand All @@ -16,6 +17,7 @@ ignored_warnings_from = [
]
# Enable new EVM codegen
via_ir = true
fs_permissions = [{access = "read-write", path = "out"}, { access = "read", path = "lib"}]

[rpc_endpoints]
sepolia = "${SEPOLIA_RPC_URL}"
Expand Down
2 changes: 1 addition & 1 deletion ethexe/contracts/lib/openzeppelin-contracts
2 changes: 1 addition & 1 deletion ethexe/contracts/lib/openzeppelin-contracts-upgradeable
2 changes: 1 addition & 1 deletion ethexe/contracts/lib/openzeppelin-foundry-upgrades
Submodule openzeppelin-foundry-upgrades updated 34 files
+7 −4 .gitignore
+3 −0 .soldeerignore
+21 −0 CHANGELOG.md
+37 −20 README.md
+4 −0 docs/modules/api/pages/Options.adoc
+34 −0 docs/modules/api/pages/api-foundry-upgrades.adoc
+1 −1 docs/modules/pages/foundry-defender.adoc
+33 −21 docs/modules/pages/foundry-upgrades.adoc
+17 −1 foundry.toml
+5 −3 package.json
+19 −0 scripts/test-reference-builds.sh
+36 −1 src/Options.sol
+12 −0 src/Upgrades.sol
+56 −13 src/internal/Core.sol
+5 −1 src/internal/DefenderDeploy.sol
+2 −2 src/internal/Versions.sol
+0 −0 test-profiles/build-info-v1/src/.gitkeep
+6 −0 test-profiles/build-info-v1/test/contracts/MyContract.sol
+0 −0 test-profiles/build-info-v2-bad/src/.gitkeep
+32 −0 test-profiles/build-info-v2-bad/test/Upgrades.t.sol
+7 −0 test-profiles/build-info-v2-bad/test/contracts/MyContract.sol
+0 −0 test-profiles/build-info-v2-reference-contract/src/.gitkeep
+21 −0 test-profiles/build-info-v2-reference-contract/test/Upgrades.t.sol
+7 −0 test-profiles/build-info-v2-reference-contract/test/contracts/MyContract.sol
+0 −0 test-profiles/build-info-v2/src/.gitkeep
+20 −0 test-profiles/build-info-v2/test/Upgrades.t.sol
+8 −0 test-profiles/build-info-v2/test/contracts/MyContract.sol
+103 −13 test/Upgrades.t.sol
+40 −0 test/contracts/HasOwner.sol
+22 −0 test/contracts/UpgradeInterfaceVersions.sol
+104 −0 test/internal/Core.t.sol
+17 −23 test/internal/DefenderDeploy.t.sol
+18 −0 test/internal/StringHelper.sol
+108 −36 yarn.lock
2 changes: 1 addition & 1 deletion ethexe/contracts/lib/symbiotic-core
Submodule symbiotic-core updated 197 files
101 changes: 74 additions & 27 deletions ethexe/contracts/src/Middleware.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import {IMigratableEntity} from "symbiotic-core/src/interfaces/common/IMigratabl

import {MapWithTimeData} from "./libraries/MapWithTimeData.sol";

// TODO: document all functions and variables
// TODO: implement election logic
// TODO (asap): document all functions and variables
// TODO (asap): implement rewards distribution
// TODO (asap): add validators commission
// TODO: implement forced operators removal
// TODO: implement forced vaults removal
// TODO: implement rewards distribution
// TODO: use hints for simbiotic calls
// TODO: use hints for symbiotic calls
contract Middleware {
using EnumerableMap for EnumerableMap.AddressToUintMap;
using MapWithTimeData for EnumerableMap.AddressToUintMap;
Expand All @@ -47,8 +47,8 @@ contract Middleware {
error VetoDurationTooShort();
error VetoDurationTooLong();
error IncompatibleVaultVersion();
error NotRegistredVault();
error NotRegistredOperator();
error NotRegisteredVault();
error NotRegisteredOperator();
error RoleMismatch();
error ResolverMismatch();
error ResolverSetDelayTooLong();
Expand All @@ -72,7 +72,7 @@ contract Middleware {
struct Config {
uint48 eraDuration;
uint48 minVaultEpochDuration;
uint48 operatoraGracePeriod;
uint48 operatorGracePeriod;
uint48 vaultGracePeriod;
uint48 minVetoDuration;
uint48 minSlashExecutionDelay;
Expand All @@ -94,7 +94,7 @@ contract Middleware {

uint48 public immutable eraDuration;
uint48 public immutable minVaultEpochDuration;
uint48 public immutable operatoraGracePeriod;
uint48 public immutable operatorGracePeriod;
uint48 public immutable vaultGracePeriod;
uint48 public immutable minVetoDuration;
uint48 public immutable minSlashExecutionDelay;
Expand All @@ -107,11 +107,12 @@ contract Middleware {
address public immutable networkOptIn;
address public immutable middlewareService;
address public immutable collateral;
address public immutable roleSlashRequester;
address public immutable roleSlashExecutor;
address public immutable vetoResolver;
bytes32 public immutable subnetwork;

address public roleSlashRequester;
address public roleSlashExecutor;

EnumerableMap.AddressToUintMap private operators;
EnumerableMap.AddressToUintMap private vaults;

Expand All @@ -120,7 +121,7 @@ contract Middleware {

eraDuration = cfg.eraDuration;
minVaultEpochDuration = cfg.minVaultEpochDuration;
operatoraGracePeriod = cfg.operatoraGracePeriod;
operatorGracePeriod = cfg.operatorGracePeriod;
vaultGracePeriod = cfg.vaultGracePeriod;
minVetoDuration = cfg.minVetoDuration;
minSlashExecutionDelay = cfg.minSlashExecutionDelay;
Expand All @@ -144,6 +145,14 @@ contract Middleware {
INetworkMiddlewareService(middlewareService).setMiddleware(address(this));
}

function changeSlashRequester(address newRole) external _onlyRole(roleSlashRequester) {
roleSlashRequester = newRole;
}

function changeSlashExecutor(address newRole) external _onlyRole(roleSlashExecutor) {
roleSlashExecutor = newRole;
}

// TODO: Check that total stake is big enough
function registerOperator() external {
if (!IRegistry(operatorRegistry).isEntity(msg.sender)) {
Expand All @@ -166,7 +175,7 @@ contract Middleware {
function unregisterOperator(address operator) external {
(, uint48 disabledTime) = operators.getTimes(operator);

if (disabledTime == 0 || Time.timestamp() < disabledTime + operatoraGracePeriod) {
if (disabledTime == 0 || Time.timestamp() < disabledTime + operatorGracePeriod) {
revert OperatorGracePeriodNotPassed();
}

Expand Down Expand Up @@ -267,12 +276,50 @@ contract Middleware {
vaults.remove(vault);
}

function getOperatorStakeAt(address operator, uint48 ts)
external
view
_validTimestamp(ts)
returns (uint256 stake)
{
function makeElectionAt(uint48 ts, uint256 maxValidators) public view returns (address[] memory) {
require(maxValidators > 0, "Max validators must be greater than zero");

(address[] memory activeOperators, uint256[] memory stakes) = getActiveOperatorsStakeAt(ts);

if (activeOperators.length <= maxValidators) {
return activeOperators;
}

// Bubble sort descending
uint256 n = activeOperators.length;
for (uint256 i = 0; i < n; i++) {
for (uint256 j = 0; j < n - 1 - i; j++) {
if (stakes[j] < stakes[j + 1]) {
(stakes[j], stakes[j + 1]) = (stakes[j + 1], stakes[j]);
(activeOperators[j], activeOperators[j + 1]) = (activeOperators[j + 1], activeOperators[j]);
}
}
}

// Choose between validators with the same stake
uint256 sameStakeCount = 1;
uint256 lastStake = stakes[maxValidators - 1];
for (uint256 i = maxValidators; i < activeOperators.length; i++) {
if (stakes[i] != lastStake) {
break;
}
sameStakeCount += 1;
}

if (sameStakeCount > 1) {
// If there are multiple validators with the same stake, choose one randomly
uint256 randomIndex = uint256(keccak256(abi.encodePacked(ts))) % sameStakeCount;
activeOperators[maxValidators - 1] = activeOperators[maxValidators + randomIndex - 1];
}

assembly {
mstore(activeOperators, maxValidators)
}

return activeOperators;
}

function getOperatorStakeAt(address operator, uint48 ts) public view _validTimestamp(ts) returns (uint256 stake) {
(uint48 enabledTime, uint48 disabledTime) = operators.getTimes(operator);
if (!_wasActiveAt(enabledTime, disabledTime, ts)) {
return 0;
Expand All @@ -281,7 +328,7 @@ contract Middleware {
stake = _collectOperatorStakeFromVaultsAt(operator, ts);
}

// TODO: change return siggnature
// TODO: change return signature
function getActiveOperatorsStakeAt(uint48 ts)
public
view
Expand Down Expand Up @@ -315,14 +362,14 @@ contract Middleware {
for (uint256 i; i < data.length; ++i) {
SlashData calldata slashData = data[i];
if (!operators.contains(slashData.operator)) {
revert NotRegistredOperator();
revert NotRegisteredOperator();
}

for (uint256 j; j < slashData.vaults.length; ++j) {
VaultSlashData calldata vaultData = slashData.vaults[j];

if (!vaults.contains(vaultData.vault)) {
revert NotRegistredVault();
revert NotRegisteredVault();
}

address slasher = IVault(vaultData.vault).slasher();
Expand All @@ -338,7 +385,7 @@ contract Middleware {
SlashIdentifier calldata slash = slashes[i];

if (!vaults.contains(slash.vault)) {
revert NotRegistredVault();
revert NotRegisteredVault();
}

IVetoSlasher(IVault(slash.vault).slasher()).executeSlash(slash.index, new bytes(0));
Expand Down Expand Up @@ -388,7 +435,7 @@ contract Middleware {
// Operator grace period cannot be smaller than minimum vaults epoch duration.
// Otherwise, it would be impossible to do slash in the next era sometimes.
require(
cfg.operatoraGracePeriod >= cfg.minVaultEpochDuration,
cfg.operatorGracePeriod >= cfg.minVaultEpochDuration,
"Operator grace period must be bigger than min vaults epoch duration"
);

Expand All @@ -402,16 +449,16 @@ contract Middleware {
// Give some time for the resolvers to veto slashes.
require(cfg.minVetoDuration > 0, "Veto duration cannot be zero");

// Simbiotic guarantees that any veto slasher has veto duration less than vault epoch duration.
// But we also want to guaratie that there is some time to execute the slash.
// Symbiotic guarantees that any veto slasher has veto duration less than vault epoch duration.
// But we also want to guarantee that there is some time to execute the slash.
require(cfg.minSlashExecutionDelay > 0, "Min slash execution delay cannot be zero");
require(
cfg.minVetoDuration + cfg.minSlashExecutionDelay <= cfg.minVaultEpochDuration,
"Veto duration and slash execution delay must be less than ot equal to min vaults epoch duration"
);

// In order to be able to change resolver, we need to limit max delay in epochs.
// `3` - is minimal number of epochs, which is simbiotic veto slasher impl restrictions.
// `3` - is minimal number of epochs, which is symbiotic veto slasher impl restrictions.
require(cfg.maxResolverSetEpochsDelay >= 3, "Resolver set epochs delay must be at least 3");
}

Expand All @@ -422,7 +469,7 @@ contract Middleware {
revert IncorrectTimestamp();
}

uint48 gracePeriod = operatoraGracePeriod < vaultGracePeriod ? operatoraGracePeriod : vaultGracePeriod;
uint48 gracePeriod = operatorGracePeriod < vaultGracePeriod ? operatorGracePeriod : vaultGracePeriod;
if (ts + gracePeriod <= Time.timestamp()) {
revert IncorrectTimestamp();
}
Expand Down
Loading

0 comments on commit 427e6d3

Please sign in to comment.