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

feat: Make CSVerifier pausable #379

Merged
merged 4 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
26 changes: 19 additions & 7 deletions script/DeployBase.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ abstract contract DeployBase is Script {
),
pivotSlot: Slot.wrap(
uint64(config.verifierSupportedEpoch * config.slotsPerEpoch)
)
),
admin: deployer
});

accounting.initialize({
Expand Down Expand Up @@ -259,11 +260,18 @@ abstract contract DeployBase is Script {
_avgPerfLeewayBP: config.avgPerfLeewayBP
});

address gateSeal = _deployGateSeal();
address[] memory sealables = new address[](4);
sealables[0] = address(csm);
sealables[1] = address(accounting);
sealables[2] = address(oracle);
sealables[3] = address(verifier);
address gateSeal = _deployGateSeal(sealables);

csm.grantRole(csm.PAUSE_ROLE(), gateSeal);
oracle.grantRole(oracle.PAUSE_ROLE(), gateSeal);
accounting.grantRole(accounting.PAUSE_ROLE(), gateSeal);
verifier.grantRole(verifier.PAUSE_ROLE(), gateSeal);

accounting.grantRole(
accounting.SET_BOND_CURVE_ROLE(),
config.setResetBondCurveAddress
Expand Down Expand Up @@ -291,6 +299,12 @@ abstract contract DeployBase is Script {
csm.grantRole(csm.DEFAULT_ADMIN_ROLE(), config.aragonAgent);
csm.revokeRole(csm.DEFAULT_ADMIN_ROLE(), deployer);

verifier.grantRole(
verifier.DEFAULT_ADMIN_ROLE(),
config.aragonAgent
);
verifier.revokeRole(verifier.DEFAULT_ADMIN_ROLE(), deployer);

accounting.grantRole(
accounting.DEFAULT_ADMIN_ROLE(),
config.aragonAgent
Expand Down Expand Up @@ -350,14 +364,12 @@ abstract contract DeployBase is Script {
return address(proxy);
}

function _deployGateSeal() internal returns (address) {
function _deployGateSeal(
address[] memory sealables
) internal returns (address) {
IGateSealFactory gateSealFactory = IGateSealFactory(
config.gateSealFactory
);
address[] memory sealables = new address[](3);
sealables[0] = address(csm);
sealables[1] = address(accounting);
sealables[2] = address(oracle);

address committee = config.sealingCommittee == address(0)
? deployer
Expand Down
10 changes: 7 additions & 3 deletions script/DeployCSVerifierElectra.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct Config {
Slot firstSupportedSlot;
Slot pivotSlot;
uint64 slotsPerEpoch;
address admin;
}

// Check the constants below via `yarn run gindex`.
Expand Down Expand Up @@ -63,7 +64,8 @@ abstract contract DeployCSVerifier is Script {
gIHistoricalSummariesPrev: config.gIHistoricalSummariesPrev,
gIHistoricalSummariesCurr: config.gIHistoricalSummariesCurr,
firstSupportedSlot: config.firstSupportedSlot,
pivotSlot: config.pivotSlot
pivotSlot: config.pivotSlot,
admin: config.admin
});
console.log("CSVerifier deployed at:", address(verifier));
}
Expand All @@ -82,7 +84,8 @@ contract DeployCSVerifierHolesky is DeployCSVerifier {
gIHistoricalSummariesPrev: HISTORICAL_SUMMARIES_DENEB,
gIHistoricalSummariesCurr: HISTORICAL_SUMMARIES_ELECTRA,
firstSupportedSlot: Slot.wrap(950272), // 269_568 * 32, @see https://github.com/eth-clients/mainnet/blob/main/metadata/config.yaml#L52
pivotSlot: Slot.wrap(0) // TODO: Update with Electra slot.
pivotSlot: Slot.wrap(0), // TODO: Update with Electra slot.
admin: 0xE92329EC7ddB11D25e25b3c21eeBf11f15eB325d // Aragon Agent
});
}
}
Expand All @@ -100,7 +103,8 @@ contract DeployCSVerifierMainnet is DeployCSVerifier {
gIHistoricalSummariesPrev: HISTORICAL_SUMMARIES_DENEB,
gIHistoricalSummariesCurr: HISTORICAL_SUMMARIES_ELECTRA,
firstSupportedSlot: Slot.wrap(8626176), // 29_696 * 32, @see https://github.com/eth-clients/holesky/blob/main/metadata/config.yaml#L38
pivotSlot: Slot.wrap(0) // TODO: Update with Electra slot.
pivotSlot: Slot.wrap(0), // TODO: Update with Electra slot.
admin: 0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c // Aragon Agent
});
}
}
18 changes: 17 additions & 1 deletion script/DeployImplementationsBase.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,24 @@ abstract contract DeployImplementationsBase is DeployBase {
),
pivotSlot: Slot.wrap(
uint64(config.verifierSupportedEpoch * config.slotsPerEpoch)
)
),
admin: deployer
});

address[] memory sealables = new address[](4);
sealables[0] = address(csm);
sealables[1] = address(accounting);
sealables[2] = address(oracle);
sealables[3] = address(verifier);
gateSeal = _deployGateSeal(sealables);

verifier.grantRole(verifier.PAUSE_ROLE(), address(gateSeal));
verifier.grantRole(
verifier.DEFAULT_ADMIN_ROLE(),
config.aragonAgent
);
verifier.revokeRole(verifier.DEFAULT_ADMIN_ROLE(), deployer);

JsonObj memory deployJson = Json.newObj();
deployJson.set("CSModuleImpl", address(csmImpl));
deployJson.set("CSAccountingImpl", address(accountingImpl));
Expand All @@ -91,6 +106,7 @@ abstract contract DeployImplementationsBase is DeployBase {
deployJson.set("CSVerifier", address(verifier));
deployJson.set("CSEarlyAdoption", address(earlyAdoption));
deployJson.set("HashConsensus", address(hashConsensus));
deployJson.set("GateSeal", address(gateSeal));
deployJson.set("git-ref", gitRef);
vm.writeJson(
deployJson.str,
Expand Down
21 changes: 21 additions & 0 deletions script/fork-helpers/SimulateVote.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { DeploymentFixtures } from "test/helpers/Fixtures.sol";
import { IStakingRouter } from "../../src/interfaces/IStakingRouter.sol";
import { OssifiableProxy } from "../../src/lib/proxy/OssifiableProxy.sol";
import { CSModule } from "../../src/CSModule.sol";
import { CSAccounting } from "../../src/CSAccounting.sol";
import { CSFeeOracle } from "../../src/CSFeeOracle.sol";
import { IBurner } from "../../src/interfaces/IBurner.sol";
import { ForkHelpersCommon } from "./Common.sol";

Expand Down Expand Up @@ -100,10 +102,29 @@ contract SimulateVote is Script, DeploymentFixtures, ForkHelpersCommon {

address admin = _prepareAdmin(deploymentConfig.csm);
csm = CSModule(deploymentConfig.csm);
accounting = CSAccounting(deploymentConfig.accounting);
oracle = CSFeeOracle(deploymentConfig.oracle);

vm.startBroadcast(admin);
csm.revokeRole(csm.VERIFIER_ROLE(), address(deploymentConfig.verifier));
csm.grantRole(csm.VERIFIER_ROLE(), address(upgradeConfig.verifier));

csm.revokeRole(csm.PAUSE_ROLE(), address(deploymentConfig.gateSeal));
accounting.revokeRole(
accounting.PAUSE_ROLE(),
address(deploymentConfig.gateSeal)
);
oracle.revokeRole(
oracle.PAUSE_ROLE(),
address(deploymentConfig.gateSeal)
);

csm.grantRole(csm.PAUSE_ROLE(), address(upgradeConfig.gateSeal));
accounting.grantRole(
accounting.PAUSE_ROLE(),
address(upgradeConfig.gateSeal)
);
oracle.grantRole(oracle.PAUSE_ROLE(), address(upgradeConfig.gateSeal));
vm.stopBroadcast();
}
}
27 changes: 23 additions & 4 deletions src/CSVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pragma solidity 0.8.24;

import { ICSVerifier } from "./interfaces/ICSVerifier.sol";
import { ICSModule } from "./interfaces/ICSModule.sol";
import { AccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
import { PausableUntil } from "./lib/utils/PausableUntil.sol";

import { BeaconBlockHeader, Slot, Validator, Withdrawal } from "./lib/Types.sol";
import { GIndex } from "./lib/GIndex.sol";
Expand All @@ -22,13 +24,16 @@ function gweiToWei(uint64 amount) pure returns (uint256) {
return uint256(amount) * 1 gwei;
}

contract CSVerifier is ICSVerifier {
contract CSVerifier is ICSVerifier, AccessControlEnumerable, PausableUntil {
using { amountWei } for Withdrawal;

using SSZ for BeaconBlockHeader;
using SSZ for Withdrawal;
using SSZ for Validator;

bytes32 public constant PAUSE_ROLE = keccak256("PAUSE_ROLE");
bytes32 public constant RESUME_ROLE = keccak256("RESUME_ROLE");

// See `BEACON_ROOTS_ADDRESS` constant in the EIP-4788.
address public constant BEACON_ROOTS =
0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;
Expand Down Expand Up @@ -77,10 +82,12 @@ contract CSVerifier is ICSVerifier {
GIndex gIHistoricalSummariesPrev,
GIndex gIHistoricalSummariesCurr,
Slot firstSupportedSlot,
Slot pivotSlot
Slot pivotSlot,
address admin
) {
if (withdrawalAddress == address(0)) revert ZeroWithdrawalAddress();
if (module == address(0)) revert ZeroModuleAddress();
if (admin == address(0)) revert ZeroAdminAddress();

if (slotsPerEpoch == 0) revert InvalidChainConfig();
if (firstSupportedSlot > pivotSlot) revert InvalidPivotSlot();
Expand All @@ -101,6 +108,18 @@ contract CSVerifier is ICSVerifier {

FIRST_SUPPORTED_SLOT = firstSupportedSlot;
PIVOT_SLOT = pivotSlot;

_grantRole(DEFAULT_ADMIN_ROLE, admin);
}

/// @inheritdoc ICSVerifier
function resume() external onlyRole(RESUME_ROLE) {
_resume();
}

/// @inheritdoc ICSVerifier
function pauseFor(uint256 duration) external onlyRole(PAUSE_ROLE) {
_pauseFor(duration);
}

/// @inheritdoc ICSVerifier
Expand All @@ -109,7 +128,7 @@ contract CSVerifier is ICSVerifier {
WithdrawalWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external {
) external whenResumed {
if (beaconBlock.header.slot < FIRST_SUPPORTED_SLOT) {
revert UnsupportedSlot(beaconBlock.header.slot);
}
Expand Down Expand Up @@ -151,7 +170,7 @@ contract CSVerifier is ICSVerifier {
WithdrawalWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external {
) external whenResumed {
if (beaconBlock.header.slot < FIRST_SUPPORTED_SLOT) {
revert UnsupportedSlot(beaconBlock.header.slot);
}
Expand Down
12 changes: 12 additions & 0 deletions src/interfaces/ICSVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ interface ICSVerifier {
error UnsupportedSlot(Slot slot);
error ZeroModuleAddress();
error ZeroWithdrawalAddress();
error ZeroAdminAddress();
error InvalidPivotSlot();

function PAUSE_ROLE() external view returns (bytes32);

function RESUME_ROLE() external view returns (bytes32);

function BEACON_ROOTS() external view returns (address);

function SLOTS_PER_EPOCH() external view returns (uint64);
Expand All @@ -87,6 +92,13 @@ interface ICSVerifier {

function MODULE() external view returns (ICSModule);

/// @notice Pause write methods calls for `duration` seconds
/// @param duration Duration of the pause in seconds
function pauseFor(uint256 duration) external;

/// @notice Resume write methods calls
function resume() external;

/// @notice Verify withdrawal proof and report withdrawal to the module for valid proofs
/// @param beaconBlock Beacon block header
/// @param witness Withdrawal witness against the `beaconBlock`'s state root.
Expand Down
Loading
Loading