The _selectPresidentRecursive
function used in the ranked choice voting contract is vulnerable to a Denial of Service (DoS) attack due to inefficient handling of recursive calls and large candidate lists. The recursive structure, combined with nested loops, can lead to gas exhaustion, which may prevent the selectPresident()
function from successfully completing and selecting a new president.
The _selectPresidentRecursive
function is designed to eliminate candidates with the fewest votes in each round until only one candidate remains. However, the use of recursion and nested loops makes the function highly susceptible to gas exhaustion, particularly when there is a large number of voters and candidates.
The key issues contributing to the vulnerability are:
Recursion Depth:
The function calls itself recursively for each round of candidate elimination. In each round, one candidate is eliminated, and the function is called again with a reduced candidate list.
If the number of candidates is large, this recursive process can exhaust the available gas, resulting in the function failing to complete.
Inefficient Looping:
The outer loop iterates over all voters, and the inner loop iterates over each voter's ranking of candidates. This nested loop structure is inefficient and can consume significant amounts of gas when the number of voters or ranked candidates is large.
No Gas Optimization:
There are no gas-saving mechanisms (such as batching or limiting the number of candidates processed in a single transaction), which increases the likelihood of running out of gas as the system scales.
The selectPresident()
function is a critical part of the contract's functionality, and gas exhaustion in _selectPresidentRecursive
can lead to the function being unusable. As a result, the voting process could be blocked, leaving the contract in a state where no new president can be selected.
This creates a DoS scenario where users can no longer interact with the contract as intended, undermining the core purpose of the voting system.
Manual Review
Replace Recursive Calls with Iterative Logic:
Refactor the _selectPresidentRecursive
function to use an iterative process instead of recursion. This will prevent the risk of running out of gas due to deep recursion.
Optimize Looping:
Optimize the nested loop structure to reduce gas consumption. Consider using mappings or other data structures to avoid iterating through large arrays multiple times.
Implement gas-efficient mechanisms to tally votes, such as batch processing or limiting the number of candidates processed in a single transaction.
Introduce Batching:
Implement a system where candidate elimination can be broken down into multiple transactions, allowing the process to continue across multiple blocks without exhausting gas in a single transaction.
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.