
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 result
This 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