Skip to content

Commit

Permalink
feat: Remove processSlashingProof (#373)
Browse files Browse the repository at this point in the history
Co-authored-by: madlabman <[email protected]>
  • Loading branch information
dgusakov and madlabman authored Dec 19, 2024
1 parent 093a2a1 commit f183eb5
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 173 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"gindex": "node script/gindex.mjs"
},
"dependencies": {
"@lodestar/types": "^1.18.1",
"@lodestar/types": "^1.23.1",
"@openzeppelin/contracts": "5.0.2",
"@openzeppelin/contracts-upgradeable": "5.0.2",
"@openzeppelin/merkle-tree": "^1.0.6",
Expand Down
106 changes: 106 additions & 0 deletions script/DeployCSVerifierElectra.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// SPDX-FileCopyrightText: 2024 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

// Usage: forge script ./script/DeployCSVerifierElectra.s.sol:DeployCSVerifier[Holesky|Mainnet]

pragma solidity 0.8.24;

import { Script } from "forge-std/Script.sol";
import { console2 as console } from "forge-std/console2.sol";

import { CSVerifier } from "../src/CSVerifier.sol";
import { GIndex } from "../src/lib/GIndex.sol";
import { Slot } from "../src/lib/Types.sol";

struct Config {
address withdrawalVault;
address module;
GIndex gIFirstWithdrawalPrev;
GIndex gIFirstWithdrawalCurr;
GIndex gIFirstValidatorPrev;
GIndex gIFirstValidatorCurr;
GIndex gIHistoricalSummariesPrev;
GIndex gIHistoricalSummariesCurr;
Slot firstSupportedSlot;
Slot pivotSlot;
uint64 slotsPerEpoch;
}

// Check the constants below via `yarn run gindex`.

GIndex constant HISTORICAL_SUMMARIES_DENEB = GIndex.wrap(
0x0000000000000000000000000000000000000000000000000000000000003b00
);
GIndex constant FIRST_WITHDRAWAL_DENEB = GIndex.wrap(
0x0000000000000000000000000000000000000000000000000000000000e1c004
);
GIndex constant FIRST_VALIDATOR_DENEB = GIndex.wrap(
0x0000000000000000000000000000000000000000000000000056000000000028
);

GIndex constant HISTORICAL_SUMMARIES_ELECTRA = GIndex.wrap(
0x0000000000000000000000000000000000000000000000000000000000005b00
);
GIndex constant FIRST_WITHDRAWAL_ELECTRA = GIndex.wrap(
0x000000000000000000000000000000000000000000000000000000000161c004
);
GIndex constant FIRST_VALIDATOR_ELECTRA = GIndex.wrap(
0x0000000000000000000000000000000000000000000000000096000000000028
);

abstract contract DeployCSVerifier is Script {
Config internal config;

function run() public {
CSVerifier verifier = new CSVerifier({
withdrawalAddress: config.withdrawalVault,
module: config.module,
slotsPerEpoch: config.slotsPerEpoch,
gIFirstWithdrawalPrev: config.gIFirstWithdrawalPrev,
gIFirstWithdrawalCurr: config.gIFirstWithdrawalCurr,
gIFirstValidatorPrev: config.gIFirstValidatorPrev,
gIFirstValidatorCurr: config.gIFirstValidatorCurr,
gIHistoricalSummariesPrev: config.gIHistoricalSummariesPrev,
gIHistoricalSummariesCurr: config.gIHistoricalSummariesCurr,
firstSupportedSlot: config.firstSupportedSlot,
pivotSlot: config.pivotSlot
});
console.log("CSVerifier deployed at:", address(verifier));
}
}

contract DeployCSVerifierHolesky is DeployCSVerifier {
constructor() {
config = Config({
withdrawalVault: 0xF0179dEC45a37423EAD4FaD5fCb136197872EAd9,
module: 0x4562c3e63c2e586cD1651B958C22F88135aCAd4f,
slotsPerEpoch: 32,
gIFirstWithdrawalPrev: FIRST_WITHDRAWAL_DENEB,
gIFirstWithdrawalCurr: FIRST_WITHDRAWAL_ELECTRA,
gIFirstValidatorPrev: FIRST_VALIDATOR_DENEB,
gIFirstValidatorCurr: FIRST_VALIDATOR_ELECTRA,
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.
});
}
}

contract DeployCSVerifierMainnet is DeployCSVerifier {
constructor() {
config = Config({
withdrawalVault: 0xB9D7934878B5FB9610B3fE8A5e441e8fad7E293f,
module: 0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F,
slotsPerEpoch: 32,
gIFirstWithdrawalPrev: FIRST_WITHDRAWAL_DENEB,
gIFirstWithdrawalCurr: FIRST_WITHDRAWAL_ELECTRA,
gIFirstValidatorPrev: FIRST_VALIDATOR_DENEB,
gIFirstValidatorCurr: FIRST_VALIDATOR_ELECTRA,
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.
});
}
}
4 changes: 2 additions & 2 deletions script/DeployMainnet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ contract DeployMainnet is DeployBase {
config.oracleMembers[4] = 0x007DE4a5F7bc37E2F26c0cb2E8A95006EE9B89b5; // P2P
config.oracleMembers[5] = 0xc79F702202E3A6B0B6310B537E786B9ACAA19BAf; // Chainlayer
config.oracleMembers[6] = 0x61c91ECd902EB56e314bB2D5c5C07785444Ea1c8; // bloXroute
config.oracleMembers[7] = 0x1Ca0fEC59b86F549e1F1184d97cb47794C8Af58d; // Instadapp
config.oracleMembers[8] = 0xe57B3792aDCc5da47EF4fF588883F0ee0c9835C9; // MatrixedLink
config.oracleMembers[7] = 0xe57B3792aDCc5da47EF4fF588883F0ee0c9835C9; // MatrixedLink
config.oracleMembers[8] = 0x73181107c8D9ED4ce0bbeF7A0b4ccf3320C41d12; // Instadapp
config.hashConsensusQuorum = 5;
// Verifier
// NOTE: Deneb fork gIndexes. Should be updated according to `config.verifierSupportedEpoch` fork epoch if needed
Expand Down
4 changes: 2 additions & 2 deletions script/gindex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import { concatGindices } from "@chainsafe/persistent-merkle-tree";
import { ssz } from "@lodestar/types";

for (const fork of ["deneb"]) {
/** @type ssz.deneb */
for (const fork of ["deneb", "electra"]) {
/** @type ssz.deneb|ssz.electra */
const Fork = ssz[fork];

{
Expand Down
51 changes: 0 additions & 51 deletions src/CSVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,57 +115,6 @@ contract CSVerifier is ICSVerifier {
PIVOT_SLOT = pivotSlot;
}

/// @notice Verify slashing proof and report slashing to the module for valid proofs
/// @param beaconBlock Beacon block header
/// @param witness Slashing witness
/// @param nodeOperatorId ID of the Node Operator
/// @param keyIndex Index of the validator key in the Node Operator's key storage
function processSlashingProof(
ProvableBeaconBlockHeader calldata beaconBlock,
SlashingWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external {
if (beaconBlock.header.slot < FIRST_SUPPORTED_SLOT) {
revert UnsupportedSlot(beaconBlock.header.slot);
}

{
bytes32 trustedHeaderRoot = _getParentBlockRoot(
beaconBlock.rootsTimestamp
);
if (trustedHeaderRoot != beaconBlock.header.hashTreeRoot()) {
revert InvalidBlockHeader();
}
}

bytes memory pubkey = MODULE.getSigningKeys(
nodeOperatorId,
keyIndex,
1
);

Validator memory validator = Validator({
pubkey: pubkey,
withdrawalCredentials: witness.withdrawalCredentials,
effectiveBalance: witness.effectiveBalance,
slashed: true,
activationEligibilityEpoch: witness.activationEligibilityEpoch,
activationEpoch: witness.activationEpoch,
exitEpoch: witness.exitEpoch,
withdrawableEpoch: witness.withdrawableEpoch
});

SSZ.verifyProof({
proof: witness.validatorProof,
root: beaconBlock.header.stateRoot,
leaf: validator.hashTreeRoot(),
gI: _getValidatorGI(witness.validatorIndex, beaconBlock.header.slot)
});

MODULE.submitInitialSlashing(nodeOperatorId, keyIndex);
}

/// @notice Verify withdrawal proof and report withdrawal to the module for valid proofs
/// @param beaconBlock Beacon block header
/// @param witness Withdrawal witness
Expand Down
8 changes: 0 additions & 8 deletions src/interfaces/ICSVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,6 @@ interface ICSVerifier {
bytes32[] proof;
}

/// @notice `witness` is a slashing witness against the `beaconBlock`'s state root.
function processSlashingProof(
ProvableBeaconBlockHeader calldata beaconBlock,
SlashingWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external;

/// @notice `witness` is a withdrawal witness against the `beaconBlock`'s state root.
function processWithdrawalProof(
ProvableBeaconBlockHeader calldata beaconBlock,
Expand Down
83 changes: 0 additions & 83 deletions test/CSVerifier.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -187,89 +187,6 @@ contract CSVerifierSlashingTest is CSVerifierTestBase {
pivotSlot: Slot.wrap(100_500)
});
}

function test_processSlashingProof() public {
SlashingFixture memory fixture = abi.decode(
_readFixture("slashing.json"),
(SlashingFixture)
);

_setMocksSlashing(fixture);

verifier.processSlashingProof(
fixture.beaconBlock,
fixture.witness,
0,
0
);
}

function test_processSlashingProof_RevertWhen_UnsupportedSlot() public {
SlashingFixture memory fixture = abi.decode(
_readFixture("slashing.json"),
(SlashingFixture)
);

_setMocksSlashing(fixture);

fixture.beaconBlock.header.slot = verifier.FIRST_SUPPORTED_SLOT().dec();

vm.expectRevert(
abi.encodeWithSelector(
CSVerifier.UnsupportedSlot.selector,
fixture.beaconBlock.header.slot
)
);
verifier.processSlashingProof(
fixture.beaconBlock,
fixture.witness,
0,
0
);
}

function test_processSlashingProof_RevertWhen_InvalidBlockHeader() public {
SlashingFixture memory fixture = abi.decode(
_readFixture("slashing.json"),
(SlashingFixture)
);

_setMocksSlashing(fixture);

vm.mockCall(
verifier.BEACON_ROOTS(),
abi.encode(fixture.beaconBlock.rootsTimestamp),
abi.encode("lol")
);

vm.expectRevert(CSVerifier.InvalidBlockHeader.selector);
verifier.processSlashingProof(
fixture.beaconBlock,
fixture.witness,
0,
0
);
}

function _setMocksSlashing(SlashingFixture memory fixture) internal {
vm.mockCall(
verifier.BEACON_ROOTS(),
abi.encode(fixture.beaconBlock.rootsTimestamp),
abi.encode(fixture._blockRoot)
);

vm.mockCall(
address(module),
abi.encodeWithSelector(ICSModule.getSigningKeys.selector, 0, 0),
abi.encode(fixture._pubkey)
);

vm.mockCall(
address(module),
abi.encodeWithSelector(ICSModule.submitInitialSlashing.selector),
""
);
}
}

contract CSVerifierWithdrawalTest is CSVerifierTestBase {
Expand Down
Loading

0 comments on commit f183eb5

Please sign in to comment.