The function isInArray
when used at _rankCandidates()
, function contains an unbounded for loop that can cause transactions to revert due to exceeding gas limits .
https://github.com/Cyfrin/2024-09-president-elector/blob/fccb8e2b6a32404b4664fa001faa334f258b4947/src/RankedChoice.sol#L167
The current implementation of _isInArray
iterates over the entire array of voters to check if a given address is in the array. If the array size is very large (since there is no limit set for the number of voters), the loop may exceed the gas limits, causing the transaction to revert. This prevents the last voters from casting their votes and could disrupt the voting process.
Transaction Failure: Transactions can fail if the loop runs out of gas, particularly affecting voters located towards the end of the array.
Disruption in Voting Process: Valid voters may be unable to cast their votes if the function reverts due to gas limits.
Manual code review + Foundry.
If we had 30,000 voters, the transaction will revert at set Up due to running out of gas. Additionally, voters at index 25000 onwards would not be able to rank candidates
Add this to your test suite:
Use a Mapping: Replace the array with a mapping for voter validation, which provides O(1) lookup time and avoids gas issues associated with large arrays.
Set a Reasonable Maximum Voter Limits : Implement a maximum length for the voter array (eg.9000 voters) and check this limit in the constructor to prevent excessive sizes.
Update Code: Modify the constructor and _rankCandidates()
function to use a mapping instead of an array for voter validation. Here’s the code:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.