Smart Security Practices From The Best
What do Lido, Red Stone, YieldNest, and Braintrust have in common? They’ve developed effective methods for improving security without drastically increasing costs. Top-tier protocol […]
The report generation cannot be completed and submitted due to this bug.
The get_remaining_forced_validators function is designed to remove validators that are required to exit, even if the withdrawal queue is fully claimable.
def get_remaining_forced_validators(self) -> list[tuple[NodeOperatorGlobalIndex, LidoValidator]]:
"""
Returns a list of validators from NOs that are requested for forced exit.
This includes an additional scenario where enough validators have been ejected to fulfill the withdrawal requests,
but forced ejections are still necessary.
"""
result: list[tuple[NodeOperatorGlobalIndex, LidoValidator]] = []
# Extra validators limited by VEBO report
while self.index != self.max_validators_to_exit:
for no_stats in sorted(self.node_operators_stats.values(), key=self.no_remaining_forced_predicate):
if self._no_force_predicate(no_stats) == 0:
# The current and all subsequent NOs in the list has no forced validators to exit. Cycle done
return result
if no_stats.predictable_validators:
# When found Node Operator
self.index += 1
gid = (
no_stats.node_operator.staking_module.id,
no_stats.node_operator.id,
)
result.append((gid, self._eject_validator(gid)))
break
return resultThis function iterates through all node operators, sorting them in descending order based on the number of validators awaiting forced exit. This count is determined by subtracting the force_exit_to limit from predictable_validators.
def _no_force_predicate(node_operator: NodeOperatorStats) -> int:
return ValidatorExitIterator._get_expected_validators_diff(
node_operator.predictable_validators,
node_operator.force_exit_to,
)If there is no difference in the count, the loop terminates with a return statement. However, if a difference is detected, the function proceeds to remove the first validator from the exitable_validators list using the _eject_validator function.
The issue arises when a Node Operator has transient validators, which are counted in the predictable_validators but not included in exitable_validators. Consequently, if the function attempts to remove a validator when exitable_validators is empty, an IndexOutOfBounds exception occurs, halting the report generation.
The following steps lead to the described issue:
force_exit_to limit set.force_exit_to limit is adjusted to 1, necessitating the exit of 2 operators while leaving one.3 - 1 = 2.2 - 1 = 1.exitable_validators list, an uncaught exception is raised, interrupting the report processing.MEDIUM – The report generation cannot be completed and submitted due to this issue.
force_exit_to limit.force_exit_to limit and lacks exitable operators. Detecting this scenario is essential to avoid a Denial of Service situation.Meet Composable Security
Get throughly tested by the creators of Smart Contract Security Verification Standard
Let us help
Get throughly tested by the creators of Smart Contract Security Verification Standard