Skip to content

Commit

Permalink
store prev value set by DAO and return it back if case of stuck and u…
Browse files Browse the repository at this point in the history
…nstuck keys
  • Loading branch information
skhomuti committed Nov 26, 2023
1 parent 41db908 commit 4837bb9
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 10 deletions.
23 changes: 20 additions & 3 deletions src/CSModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct NodeOperator {
address proposedRewardAddress;
bool active;
uint256 targetLimit;
uint256 prevTargetLimit;
uint256 stuckPenaltyEndTimestamp;
uint256 totalExitedKeys;
uint256 totalAddedKeys;
Expand Down Expand Up @@ -650,10 +651,26 @@ contract CSModule is IStakingModule, CSModuleBase {

no.stuckValidatorsCount = stuckValidatorsCount;

if (stuckValidatorsCount == 0) {
_setTargetLimit(nodeOperatorId, false, 0);
if (stuckValidatorsCount > 0) {
// @dev the oracle can decrease target limit but can't increase it
// after unstuck, target limit will be set to previous value
if (
!no.isTargetLimitActive ||
no.targetLimit > no.totalDepositedKeys
) {
no.prevTargetLimit = no.targetLimit;
_setTargetLimit(
nodeOperatorId,
true,
no.totalDepositedKeys
);
}
} else {
_setTargetLimit(nodeOperatorId, true, no.totalDepositedKeys);
_setTargetLimit(
nodeOperatorId,
no.prevTargetLimit > 0,
no.prevTargetLimit
);
}

emit StuckSigningKeysCountChanged(
Expand Down
110 changes: 103 additions & 7 deletions test/CSModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,89 @@ contract CsmUpdateStuckValidatorsCount is CSMCommon {
assertTrue(summary.isTargetLimitActive, "isTargetLimitActive is false");
}

function test_updateStuckValidatorsCount_Unstuck() public {
uint256 noId = createNodeOperator();
csm.vetKeys(noId, 1);
csm.obtainDepositData(1, "");

csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000001))
);

vm.expectEmit(true, true, false, true, address(csm));
emit TargetValidatorsCountChanged(noId, 0);
vm.expectEmit(true, true, false, true, address(csm));
emit StuckSigningKeysCountChanged(noId, 0);
csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000000))
);
NodeOperatorSummary memory summary = getNodeOperatorSummary(noId);
assertEq(
summary.stuckValidatorsCount,
0,
"stuckValidatorsCount should be zero"
);
assertEq(
summary.targetValidatorsCount,
0,
"targetValidatorsCount should be zero"
);
assertFalse(
summary.isTargetLimitActive,
"isTargetLimitActive should be false"
);
}

function test_updateStuckValidatorsCount_DecreaseLimit() public {
uint256 noId = createNodeOperator();
csm.vetKeys(noId, 1);
csm.obtainDepositData(1, "");
csm.updateTargetValidatorsLimits(noId, true, 2);

vm.expectEmit(true, true, false, true, address(csm));
emit TargetValidatorsCountChanged(noId, 1);
csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000001))
);
}

function test_updateStuckValidatorsCount_ReturnToPrevLimit() public {
uint256 noId = createNodeOperator();
csm.vetKeys(noId, 1);
csm.obtainDepositData(1, "");
csm.updateTargetValidatorsLimits(noId, true, 2);

csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000001))
);

vm.expectEmit(true, true, false, true, address(csm));
emit TargetValidatorsCountChanged(noId, 2);
csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000000))
);
NodeOperatorSummary memory summary = getNodeOperatorSummary(noId);
assertEq(
summary.stuckValidatorsCount,
0,
"stuckValidatorsCount should be zero"
);
assertEq(
summary.targetValidatorsCount,
2,
"targetValidatorsCount should return to prev value"
);
assertTrue(
summary.isTargetLimitActive,
"isTargetLimitActive should remain true"
);
}

function test_updateStuckValidatorsCount_RevertWhenNoNodeOperator() public {
vm.expectRevert(NodeOperatorDoesNotExist.selector);
csm.updateStuckValidatorsCount(
Expand Down Expand Up @@ -1198,9 +1281,7 @@ contract CsmUpdateStuckValidatorsCount is CSMCommon {
);
}

// @dev this is ugly solution to test that events are not emitted when stuckKeysCount is not changed
// we can't do it properly while vm.expectNotEmit is not implemented in forge (or smth like that)
function testFail_updateStuckValidatorsCount_NoEventWhenStuckKeysCountSame()
function test_updateStuckValidatorsCount_NoEventWhenStuckKeysCountSame()
public
{
uint256 noId = createNodeOperator();
Expand All @@ -1211,13 +1292,28 @@ contract CsmUpdateStuckValidatorsCount is CSMCommon {
bytes.concat(bytes16(0x00000000000000000000000000000001))
);

vm.expectEmit(true, true, false, true, address(csm));
emit TargetValidatorsCountChanged(noId, 1);
vm.expectEmit(true, true, false, true, address(csm));
emit StuckSigningKeysCountChanged(noId, 1);
vm.recordLogs();
csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000001))
);
Vm.Log[] memory logs = vm.getRecordedLogs();
assertEq(logs.length, 0);
}

function test_updateStuckValidatorsCount_NoEventWhenLimitSame() public {
uint256 noId = createNodeOperator();
csm.vetKeys(noId, 1);
csm.obtainDepositData(1, "");
csm.updateTargetValidatorsLimits(noId, true, 1);

vm.recordLogs();
csm.updateStuckValidatorsCount(
bytes.concat(bytes8(0x0000000000000000)),
bytes.concat(bytes16(0x00000000000000000000000000000001))
);
Vm.Log[] memory logs = vm.getRecordedLogs();
// only StuckSigningKeysCountChanged
assertEq(logs.length, 1);
}
}

0 comments on commit 4837bb9

Please sign in to comment.