Modification on Game Data Flow
On last post of SlotNSlot, several vulnerable points were found. The data flow logic is somewhat modified. In this article, some abusing scenarios for original design would be demonstrated, and the modified design will be explained in details.
Original Design
The original data flow had bankers always commit and reveal to player via Whisper, p2p messaging protocol. We believed that this would decrease the required number of transactions to the minimum of 2. This was absolutely nonsense, since the player is always the one to both commit and reveal all the seeds to the contract, which means the contract is ignorant of what happened between both parties.
Major problems included,
1. Contract doesn’t know who’s being malicious, thus not able to penalize a specific user.
2. Banker could reveal a wrong value on N, or even not reveal. Bankers don’t know the result in advance, but they could discriminate players by betting amounts and paylines played.
3. Player could commit a wrong value on SHA(N), reveal wrong values on N, M, not commit at all, or not reveal at the end. Players will always abort the result if it’s not a winning bet.
4. Because no single user could be determined to be penalized, a malicious player can deploy Denial of Service attack on slot sessions, by visiting and doing nothing.
Redesigned Model
The team tweaked the design to solve the issues mentioned. A game session will be initialized by both users submitting a final value of hashing their seeds for R rounds (i.e. SHA^R(N), SHA^R(M)). This is the same as how state-channel solutions are initialized, where R rounds of games become deterministic with those initializing commits. Here the value for R must be sufficiently large so that it won’t run out of seed before a player leaves.
i) A player visits a slot machine game contract, determines total ETHs to deposit in the game, and sends SHA^R(N) to the contract.
ii) The banker of that game receives a callback that the slot is occupied, and sends SHA^R(M). The game session between the very two users is initiated.
After the session is initialized,
iii) the player sends his betting parameters {betAmount, numLine} to the contract,
iv) the banker verifies is_valid(player_tx), reveals his preimage SHA^(R-1)(N), and whispers the player the same information, and
v) the player client draws a result with the banker’s seed, verifies is_valid(banker_tx), and reveals his preimage SHA^(R-1)(M)
iii) to v) repeats for every spin.
* is_valid(tx) will check if the opponent’s transaction has all valid inputs, gasLimit, gasPrice, etc. If a transaction is to be rejected by the contract, that shouldn’t pass the is_valid(tx) verification too.
Both participants should not proceed their steps if the previous step’s tx verification fails(i.e. the opponent had not submit valid input). The reason banker’s client sending whisper message here is solely to make the player client to immediately draw the result of the round. All the rounds in the game session are finalized when the contract achieves N-block timeout condition with a CASH OUT request. Either the player or the banker can publish a CASH OUT request to the contract, which will trigger as follows.
The game session will always update the blocknumber of each participant's last transaction mined. Say,player's last blocknumber = Np
banker's last blocknumber = Nb
CASH OUT request blocknumber = Ncthen,if |Np-Nb| > N ///one user irregularly proceeding
then [N-block gap is found]
else if Nc - max(Np,Nb) > N ///N-block passed since last round
then [N-block gap is found]
else print("request CASH OUT after ~ seconds")Here, if this "CASH OUT requester" doesn't publish any more transaction, N-block gap would definitely be found after ~ seconds such that (~ seconds) = (N+1) * avg(blocktime).
When finalizing the session with a CASH OUT, any round after the KICK request should be considered irregular, since the player shouldn’t have proceeded further after verifying the banker’s transaction with KICK=1. Thus, the contract would finalize all the rounds up to the one with KICK=1, apply the game results to both users’ balances, payout the resulting balance to the player, and update the slot contract’s totalStake to the resulting balance (i.e. finalize the session).
After all those rules in consideration, each round will finalize with following logics. Note that a finalized session would have all the rounds in it finalized, results applied to the balances, player’s balance withdrawn back to his wallet, and the banker’s balance applied to the game contract’s totalStake.
1. Every round should be finalized after the prior round is finalized. In other words, rounds should be finalized in ascending order. (this is trivial because a preimage needs its prior round to be verified). Any round with a result in either of the balances 0 ETH or less should finalize the session, and invalidate all the rounds after it.2. A round with all the inputs valid generates random numbers with both preimages sent by the player and the banker as seeds, calculates the result, and stores them.3. A round with valid inputs only for betAmount&numLine utilizes alternative seeds for the round(e.g. blockhash). The banker didn't submit his seed either on purpose or due to sudden disconnection. Because the hash chain is broken, the session is automatically finalized, and the player automatically leaves.4. A round with valid inputs only for betAmount, numLine, and the banker's preimage finalizes as a losing bet for the player. Hash chain breaks, thus session finalized.5. Any other case will finalize as a invalid round, and the session finalizes. These cases take place when both participants acted irregular.
There are still some issues remaining for this model.
i) Determining sufficient R hash chain length.
ii) Determining N-block timeout condition.
iii) Transaction overriding. (publishing multiple inputs to a single round)
iv) UX degradation when bankers purposely not whispering
v) Alternative random seed to use for round finalization case 3.
These issues are quite affected by the actual state of Ethereum blockchain at the moment such as average blocktime and gaslimit. We’ll be implementing the codes for the redesigned model, test it on both Testnet and Mainnet, and post an analysis on them. Any other issues including those mentioned above will be discussed further afterwards.
SlotNSlot team is always craving to hear suggestions, criticisms, and feedbacks for the project. Please keep your interest in our project, and help us accomplish a true DApp project.
Check out our
WebPage // Whitepaper // Github // Twitter // HipChat
*you can join our hipchat without sign up