Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Invalid

Missing GameState Transition from Committed to Revealed

Summary

Upon reviewing the contract, it is observed that the game.state is never set to GameState.Revealedand this might cause some unexpected behaviour in the game.

Vulnerability Details

When both the players have committed their moves the revealDeadline is being set in the commitMove() function as shown below:

// If both players have committed, set the reveal deadline
if (game.commitA != bytes32(0) && game.commitB != bytes32(0)) {
game.revealDeadline = block.timestamp + game.timeoutInterval;
}

But along with this the gameState is never changed to GameState.Revealed (assuming that the Revealed state is applicable when both moves have been committed). This condition is then next checked in the revealMove() function as follows:

require(game.state == GameState.Committed, "Game not in reveal phase");

However, the contract never explicitly transitions the game state to Revealed once both players have committed their moves. This could lead to the following issues:

Inconsistent Game State: Since the game state remains GameState.Committed even after both players commit their moves, the state of the game is not updated accordingly.

Also, if we assume that the game.State is set to Revealed once the moves have been revealed by both the players, still the gameState is not updated in the following line of code:

// If both players have revealed, determine the winner for this turn
if (game.moveA != Move.None && game.moveB != Move.None) {
_determineWinner(_gameId);
}

Here also the gameState is not changed explicitly.

Also in the timeoutReveal() function there is this require check done:

require(game.state == GameState.Committed, "Game not in reveal phase");

Here also the state check is incorrectly specified.

Impact

User Experience Issues: Players may not have clear visibility into the current game state. For example, they might assume they are still in the "commit phase" when in reality they should be in the "reveal phase." This could lead to confusion during gameplay.

Tools Used

Manual Review

Recommendations

1st Option:

  • Transition Game State to Revealed: After both players have committed their moves (i.e., both commitA and commitB are set), the game state should be explicitly changed to GameState.Revealed. This can be done after both players' commits are confirmed in the commitMove()function.

if (game.commitA != bytes32(0) && game.commitB != bytes32(0)) {
game.revealDeadline = block.timestamp + game.timeoutInterval;
+ game.state = GameState.Revealed; // Transition to Revealed state
}
  • Additionally, the revealMove() function should check for GameState.Revealed:

    - require(game.state == GameState.Committed, "Game not in reveal phase");
    + require(game.state == GameState.Revealed, "Game not in reveal phase");

2nd Option:

  • Transition The Game State after both the players have revealed their moves: After both players have revealed their moves, the game state should be explicitly changed to GameState.Revealed in the revealMove() function.

    if (game.moveA != Move.None && game.moveB != Move.None) {
    + game.state = GameState.Revealed; // Transition to Revealed state
    _determineWinner(_gameId);
    }
Updates

Appeal created

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational

Code suggestions or observations that do not pose a direct security risk.

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational

Code suggestions or observations that do not pose a direct security risk.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.