The commitMove()
function in the RockPaperScissors contract allows players to commit moves when the game is still in the Created
state, before Player B has officially joined. This inconsistency in state management, combined with the missing state updates in join functions, creates potential race conditions and unexpected behavior.
The issue is in the commitMove()
function (lines 192-222), which explicitly allows committing moves in either the Created
or Committed
states:
There are several issues with this implementation:
The function allows committing moves when the game is in the Created
state, which should only be possible after Player B has joined.
While there is a check to ensure Player B has joined (require(game.playerB != address(0))
), this is only applied for the first turn and first commits. For subsequent commits, the function only checks that the game is in the Committed
state.
As identified in a previous issue, the join functions (joinGameWithEth()
and joinGameWithToken()
) do not update the game state to Committed
when Player B joins, creating an inconsistency in the state management.
The commitMove()
function itself updates the game state to Committed
when the first player commits a move, which is inconsistent with the expected game flow where the state should be updated when Player B joins.
This inconsistent state management can lead to several issues:
Race Conditions: Player A could commit a move before Player B has officially joined, leading to unexpected behavior.
Inconsistent Game State: The game state doesn't accurately reflect the current stage of the game, making it harder to reason about the contract's behavior.
Potential for Exploits: Malicious players could potentially exploit these inconsistencies to gain advantages or disrupt games.
Contract Logic Confusion: The contract relies on checking the game state in multiple functions, and inconsistent state management could lead to unexpected behavior in other parts of the contract.
While this issue doesn't directly lead to fund loss, it creates confusion and potential race conditions that could impact the user experience and contract reliability.
Manual code review
Static analysis of the contract's state management
Logical analysis of game flow
Modify the commitMove()
function to only allow commits when the game is in the Committed
state:
Ensure that the join functions update the game state to Committed
when Player B joins, as recommended in the previous issue.
Remove the state update from the commitMove()
function, as the game should already be in the Committed
state when players are committing moves.
Add clear documentation about the expected state transitions in the contract to ensure consistent implementation across all functions.
These changes would ensure a more consistent and predictable state management flow throughout the contract, reducing the potential for race conditions and unexpected behavior.
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.