Skip to content

Commit 0cde2dc

Browse files
fixes #21: use merkelize in getRootHash (#24)
* use merkle tree for root hash * other fixes * chore: changes --------- Co-authored-by: Aashutosh Rathi <aashutosh@stackrlabs.xyz>
1 parent 8108f5c commit 0cde2dc

File tree

2 files changed

+25
-31
lines changed

2 files changed

+25
-31
lines changed

rollup/stackr/machine.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { State, StateMachine } from "@stackr/sdk/machine";
2-
import { solidityPackedKeccak256 } from "ethers";
2+
import { merklize } from "@stackr/sdk";
3+
import { solidityPacked } from "ethers";
34
import genesisState from "../genesis-state.json";
45
import { transitions } from "./transitions";
56

@@ -24,14 +25,13 @@ export class AppState extends State<RawState, WrappedState> {
2425
transformer() {
2526
return {
2627
wrap: () => {
27-
const games = this.state.games.reduce((acc, game) => {
28+
const games = this.state.games.reduce<WrappedState['games']>((acc, game) => {
2829
const { id, ...rest } = game;
2930
acc[id] = { ...rest };
3031
return acc;
3132
}, {});
3233
return { games };
3334
},
34-
3535
unwrap: (wrappedState: WrappedState) => {
3636
const games = Object.keys(wrappedState.games).map((id) => ({
3737
id,
@@ -43,12 +43,12 @@ export class AppState extends State<RawState, WrappedState> {
4343
};
4444
}
4545

46-
// TODO: change this to MerkleTree
47-
getRootHash() {
48-
return solidityPackedKeccak256(
49-
["string"],
50-
[JSON.stringify(this.state.games)]
46+
getRootHash(): string {
47+
const leaves = this.state.games.map(
48+
({ id, player, score }) =>
49+
solidityPacked(["string", "address", "uint256"], [id, player, score])
5150
);
51+
return merklize(leaves);
5252
}
5353
}
5454

rollup/stackr/transitions.ts

+17-23
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
import { STF, Transitions } from "@stackr/sdk/machine";
1+
import { REQUIRE, STF, Transitions } from "@stackr/sdk/machine";
22
import { hashMessage } from "ethers";
33
import { ACTIONS, GameMode } from "../../client/game/gameMode";
44
import { World } from "../../client/game/world";
55
import { AppState } from "./machine";
66

7-
export type CreateGame = {
7+
export type StartGameInput = {
88
timestamp: number;
99
};
1010

11-
export type ValidateGameInput = {
12-
gameId: number;
11+
export type EndGameInput = {
12+
gameId: string;
13+
timestamp: number;
1314
score: number;
1415
gameInputs: string;
1516
};
1617

17-
const startGame: STF<AppState, ValidateGameInput> = {
18+
const startGame: STF<AppState, StartGameInput> = {
1819
handler: ({ state, msgSender, block, emit }) => {
1920
const gameId = hashMessage(
2021
`${msgSender}::${block.timestamp}::${Object.keys(state.games).length}`
2122
);
2223

2324
state.games[gameId] = {
24-
id: gameId,
2525
score: 0,
26-
player: msgSender,
26+
player: String(msgSender),
2727
};
2828

2929
emit({
@@ -34,22 +34,15 @@ const startGame: STF<AppState, ValidateGameInput> = {
3434
},
3535
};
3636

37-
const endGame: STF<AppState, ValidateGameInput> = {
37+
const endGame: STF<AppState, EndGameInput> = {
3838
handler: ({ state, inputs, msgSender }) => {
3939
const { gameInputs, gameId, score } = inputs;
4040
const { games } = state;
41-
if (!games[gameId]) {
42-
throw new Error("Game not found");
43-
}
44-
45-
if (games[gameId].score > 0) {
46-
throw new Error("Game already ended");
47-
}
48-
49-
if (games[gameId].player !== msgSender) {
50-
throw new Error("Unauthorized to end game");
51-
}
52-
41+
// validation checks
42+
REQUIRE(!!games[gameId], "GAME_NOT_FOUND");
43+
REQUIRE(games[gameId].score === 0, "GAME_ALREADY_ENDED");
44+
REQUIRE(games[gameId].player === String(msgSender), "UNAUTHORIZED");
45+
// rerun game loop
5346
const world = new World();
5447
const gameMode = new GameMode(world, { gameId });
5548
const ticks = gameInputs
@@ -60,9 +53,10 @@ const endGame: STF<AppState, ValidateGameInput> = {
6053
gameMode.deserializeAndUpdate(1 / 60, ticks[i]);
6154
}
6255

63-
if (world.score !== score) {
64-
throw new Error(`Failed to replay: ${world.score} !== ${score}`);
65-
}
56+
REQUIRE(
57+
world.score === score,
58+
`FAILED_TO_REPLAY: ${world.score} !== ${score}`
59+
);
6660

6761
games[gameId].score = score;
6862

0 commit comments

Comments
 (0)