-
Notifications
You must be signed in to change notification settings - Fork 105
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
feat(ethexe): Support slash commitments in router #4403
base: master
Are you sure you want to change the base?
Changes from all commits
fe85580
275c6a1
2d0fce0
b0fad1d
6f18dec
41fbb4f
c440d7f
8a55708
a6f60ad
4fb714d
c4d0482
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.26; | ||
|
||
interface IMiddleware { | ||
struct VaultSlashData { | ||
address vault; | ||
uint256 amount; | ||
} | ||
|
||
struct SlashData { | ||
address operator; | ||
uint48 ts; | ||
VaultSlashData[] vaults; | ||
} | ||
|
||
struct SlashIdentifier { | ||
address vault; | ||
uint256 index; | ||
} | ||
|
||
struct Config { | ||
uint48 eraDuration; | ||
uint48 minVaultEpochDuration; | ||
uint48 operatorGracePeriod; | ||
uint48 vaultGracePeriod; | ||
uint48 minVetoDuration; | ||
uint48 minSlashExecutionDelay; | ||
uint256 maxResolverSetEpochsDelay; | ||
address vaultRegistry; | ||
uint64 allowedVaultImplVersion; | ||
uint64 vetoSlasherImplType; | ||
address operatorRegistry; | ||
address networkRegistry; | ||
address networkOptIn; | ||
address middlewareService; | ||
address collateral; | ||
address roleSlashRequester; | ||
address roleSlashExecutor; | ||
address vetoResolver; | ||
} | ||
|
||
function changeSlashRequester(address newRole) external; | ||
|
||
function changeSlashExecutor(address newRole) external; | ||
|
||
function registerOperator() external; | ||
|
||
function disableOperator() external; | ||
|
||
function enableOperator() external; | ||
|
||
function unregisterOperator(address operator) external; | ||
|
||
function registerVault(address vault) external; | ||
|
||
function disableVault(address vault) external; | ||
|
||
function enableVault(address vault) external; | ||
|
||
function unregisterVault(address vault) external; | ||
|
||
function makeElectionAt(uint48 ts, uint256 maxValidators) external view returns (address[] memory); | ||
|
||
function getOperatorStakeAt(address operator, uint48 ts) external view returns (uint256); | ||
|
||
function getActiveOperatorsStakeAt(uint48 ts) | ||
external | ||
view | ||
returns (address[] memory activeOperators, uint256[] memory stakes); | ||
|
||
function requestSlash(SlashData[] calldata data) external; | ||
|
||
function executeSlash(SlashIdentifier[] calldata slashes) external; | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||
// SPDX-License-Identifier: UNLICENSED | ||||||||||||||||||||||||||||||
pragma solidity ^0.8.26; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
import {IMiddleware} from "./Middleware.sol"; | ||||||||||||||||||||||||||||||
import {Gear} from "./libraries/Gear.sol"; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/// @title Gear.exe Router Interface | ||||||||||||||||||||||||||||||
|
@@ -65,6 +66,18 @@ interface IRouter { | |||||||||||||||||||||||||||||
/// @param codeId The code ID of the WASM implementation of the created program. | ||||||||||||||||||||||||||||||
event ProgramCreated(address actorId, bytes32 indexed codeId); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||
* @dev Emitted when a slash request is processed by the middleware. | ||||||||||||||||||||||||||||||
* @param slashData An array of SlashData structures containing details of the slash request. | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
event RequestSlashCommitmentProcessed(bytes32 indexed commitmentHash, IMiddleware.SlashData[] slashData); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||
* @dev Emitted when a slash request is executed by the middleware. | ||||||||||||||||||||||||||||||
* @param slashId An array of SlashIdentifier structures containing details of the slash execution. | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
event ExecuteSlashCommitmentProcessed(bytes32 indexed commitmentHash, IMiddleware.SlashIdentifier[] slashId); | ||||||||||||||||||||||||||||||
Comment on lines
+73
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/// @notice Emitted when the router's storage slot has been changed. | ||||||||||||||||||||||||||||||
/// @dev This is both an *informational* and *requesting* event, signaling that an authority decided to wipe the router state, rendering all previously existing codes and programs ineligible. Validators need to wipe their databases immediately. | ||||||||||||||||||||||||||||||
event StorageSlotChanged(); | ||||||||||||||||||||||||||||||
|
@@ -77,6 +90,7 @@ interface IRouter { | |||||||||||||||||||||||||||||
function mirrorImpl() external view returns (address); | ||||||||||||||||||||||||||||||
function mirrorProxyImpl() external view returns (address); | ||||||||||||||||||||||||||||||
function wrappedVara() external view returns (address); | ||||||||||||||||||||||||||||||
function middleware() external view returns (address); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
function areValidators(address[] calldata validators) external view returns (bool); | ||||||||||||||||||||||||||||||
function isValidator(address validator) external view returns (bool); | ||||||||||||||||||||||||||||||
|
@@ -115,4 +129,12 @@ interface IRouter { | |||||||||||||||||||||||||||||
/// @dev NextEraValidatorsCommitted Emitted on success. | ||||||||||||||||||||||||||||||
function commitValidators(Gear.ValidatorsCommitment calldata validatorsCommitment, bytes[] calldata signatures) | ||||||||||||||||||||||||||||||
external; | ||||||||||||||||||||||||||||||
function commitRequestSlash( | ||||||||||||||||||||||||||||||
Gear.RequestSlashCommitment calldata requestSlashCommitment, | ||||||||||||||||||||||||||||||
bytes[] calldata signatures | ||||||||||||||||||||||||||||||
) external; | ||||||||||||||||||||||||||||||
function commitExecuteSlash( | ||||||||||||||||||||||||||||||
Gear.ExecuteSlashCommitment calldata executeSlashCommitment, | ||||||||||||||||||||||||||||||
bytes[] calldata signatures | ||||||||||||||||||||||||||||||
) external; | ||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.26; | |
|
||
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; | ||
import {Gear} from "./libraries/Gear.sol"; | ||
import {IMiddleware} from "./IMiddleware.sol"; | ||
import {IMirror} from "./IMirror.sol"; | ||
import {IMirrorDecoder} from "./IMirrorDecoder.sol"; | ||
import {IRouter} from "./IRouter.sol"; | ||
|
@@ -26,6 +27,7 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient { | |
address _mirror, | ||
address _mirrorProxy, | ||
address _wrappedVara, | ||
address _middleware, | ||
uint256 _eraDuration, | ||
uint256 _electionDuration, | ||
address[] calldata _validators | ||
|
@@ -41,7 +43,7 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient { | |
Storage storage router = _router(); | ||
|
||
router.genesisBlock = Gear.newGenesis(); | ||
router.implAddresses = Gear.AddressBook(_mirror, _mirrorProxy, _wrappedVara); | ||
router.implAddresses = Gear.AddressBook(_mirror, _mirrorProxy, _wrappedVara, _middleware); | ||
router.validationSettings.signingThresholdPercentage = Gear.SIGNING_THRESHOLD_PERCENTAGE; | ||
router.computeSettings = Gear.defaultComputationSettings(); | ||
router.timelines = Gear.Timelines(_eraDuration, _electionDuration); | ||
|
@@ -110,6 +112,10 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient { | |
return _router().implAddresses.wrappedVara; | ||
} | ||
|
||
function middleware() public view returns (address) { | ||
return _router().implAddresses.middleware; | ||
} | ||
|
||
function areValidators(address[] calldata _validators) public view returns (bool) { | ||
Gear.Validators storage _currentValidators = Gear.currentEraValidators(_router()); | ||
|
||
|
@@ -323,6 +329,72 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient { | |
); | ||
} | ||
|
||
function commitRequestSlash(Gear.RequestSlashCommitment calldata commitment, bytes[] calldata signatures) | ||
external | ||
{ | ||
Storage storage router = _router(); | ||
|
||
uint256 currentEraIndex = (block.timestamp - router.genesisBlock.timestamp) / router.timelines.era; | ||
|
||
// Validate the era index | ||
require(commitment.eraIndex == currentEraIndex, "commitment era index is invalid"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is not possible to sent a slash for the previous era? for example we found that validator from the previous era did something wrong - why we cannot to sent a slash for the funds it had in the previous era? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah now I can see. I think era param should be removed from commitment. Cannot see why do we need it. Slashes have already all informations about timestamps. |
||
|
||
// Ensure the commitment window is valid | ||
uint256 eraStart = router.genesisBlock.timestamp + router.timelines.era * currentEraIndex; | ||
require(block.timestamp >= eraStart, "current era has not started yet"); | ||
Comment on lines
+343
to
+344
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is mathematically impossible case |
||
|
||
// Validate signatures | ||
bytes32 commitmentHash = Gear.requestSlashCommitmentHash(commitment); | ||
require( | ||
Gear.validateSignatures(router, keccak256(abi.encodePacked(commitmentHash)), signatures), | ||
"request slash commitment signatures verification failed" | ||
); | ||
|
||
// Ensure middleware is set | ||
address middlewareAddress = router.implAddresses.middleware; | ||
require(middlewareAddress != address(0), "Middleware address not set"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not important: Looks like over-checking. This must be checked in constructor |
||
|
||
IMiddleware middlewareInstance = IMiddleware(middlewareAddress); | ||
|
||
// Call the middleware's `requestSlash` function | ||
middlewareInstance.requestSlash(commitment.slashes); | ||
|
||
emit RequestSlashCommitmentProcessed(commitmentHash, commitment.slashes); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think is enough to sent a commitmentHash. This is cheaper. And validators could save their slashes in db by hash and access them if they need in future. |
||
} | ||
|
||
function commitExecuteSlash(Gear.ExecuteSlashCommitment calldata commitment, bytes[] calldata signatures) | ||
external | ||
{ | ||
Storage storage router = _router(); | ||
|
||
uint256 currentEraIndex = (block.timestamp - router.genesisBlock.timestamp) / router.timelines.era; | ||
|
||
// Validate the era index | ||
require(commitment.eraIndex == currentEraIndex, "commitment era index is invalid"); | ||
|
||
// Ensure the commitment window is valid | ||
uint256 eraStart = router.genesisBlock.timestamp + router.timelines.era * currentEraIndex; | ||
require(block.timestamp >= eraStart, "current era has not started yet"); | ||
|
||
// Validate signatures | ||
bytes32 commitmentHash = Gear.executeSlashCommitmentHash(commitment); | ||
require( | ||
Gear.validateSignatures(router, keccak256(abi.encodePacked(commitmentHash)), signatures), | ||
"execute slash commitment signatures verification failed" | ||
); | ||
|
||
// Ensure middleware is set | ||
address middlewareAddress = router.implAddresses.middleware; | ||
require(middlewareAddress != address(0), "Middleware address not set"); | ||
|
||
IMiddleware middlewareInstance = IMiddleware(middlewareAddress); | ||
|
||
// Call the middleware's `executeSlash` function | ||
middlewareInstance.executeSlash(commitment.slashIdentifiers); | ||
|
||
emit ExecuteSlashCommitmentProcessed(commitmentHash, commitment.slashIdentifiers); | ||
} | ||
|
||
/* Helper private functions */ | ||
|
||
function _createProgram(bytes32 _codeId, bytes32 _salt) private returns (address) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vm.computeCreateAddress(deployerAddress, deployerNonce)
is used to compute the future contract address. aftermirrorProxy = new MirrorProxy(address(router))
you need to createmiddleware
to make this address valid.