Created
February 7, 2022 06:16
-
-
Save danielkhoo/a6c82654d195d7df3208c5ec65a23a42 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.8.0 <0.9.0; | |
/** | |
* @notice Function for players to reveal their choice. The first player to reveal sets a deadline for the second player | |
* this is prevent players for abandoning the game once they know they have lost based on the revealed hash. | |
* At the end of the deadline, the player who committed can trigger a "win-by-default". | |
* If both players reveal in time, the second player's reveal will call determineWinner() and advance the game to the result phase | |
* @notice Unlike commit, players can only reveal once | |
* @param salt - a player chosen secret string from the "commit" phase used to prove their choice via a hash match | |
*/ | |
function reveal(string memory salt) | |
public | |
validGameState(activeGame[msg.sender], GameState.RevealPhase) | |
{ | |
// Get the game hash from active game mapping | |
address gameHash = activeGame[msg.sender]; | |
bool isPlayer1 = games[gameHash].player1 == msg.sender; | |
// Check that player hasn't already revealed | |
if (isPlayer1) { | |
require(games[gameHash].reveal1 == 0, "Already revealed"); | |
} else { | |
require(games[gameHash].reveal2 == 0, "Already revealed"); | |
} | |
// Verify that one of the choices + salt hashes matches commit hash | |
// Compare all three possible choices so they don't have to enter their choice again | |
bytes32 verificationHashRock = keccak256(abi.encodePacked("rock", salt)); | |
bytes32 verificationHashPaper = keccak256(abi.encodePacked("paper", salt)); | |
bytes32 verificationHashScissors = keccak256( | |
abi.encodePacked("scissors", salt) | |
); | |
bytes32 commitHash = isPlayer1 | |
? games[gameHash].commit1 | |
: games[gameHash].commit2; | |
require( | |
verificationHashRock == commitHash || | |
verificationHashPaper == commitHash || | |
verificationHashScissors == commitHash, | |
"Reveal hash doesn't match commit hash. Salt not the same as commit." | |
); | |
// Work backwards to infer their choice | |
string memory choice; | |
if (verificationHashRock == commitHash) { | |
choice = "rock"; | |
} else if (verificationHashPaper == commitHash) { | |
choice = "paper"; | |
} else { | |
choice = "scissors"; | |
} | |
// Save the revealed hash w/o salt | |
if (isPlayer1) { | |
games[gameHash].reveal1 = keccak256(abi.encodePacked(choice)); | |
} else { | |
games[gameHash].reveal2 = keccak256(abi.encodePacked(choice)); | |
} | |
// if both players revealed, determine winner | |
if (games[gameHash].reveal1 != 0 && games[gameHash].reveal2 != 0) { | |
games[gameHash].gameResult = determineWinner( | |
games[gameHash].reveal1, | |
games[gameHash].reveal2 | |
); | |
games[gameHash].gameState = GameState.ResultPhase; | |
} else { | |
// Set deadline for other player to reveal | |
games[gameHash].revealDeadline = block.timestamp + 3 minutes; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment