diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index ff95cf5..3b4a818 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -72,6 +72,12 @@ paths: moveCount: type: string format: uint64 + beforeIndex: + type: string + description: Pertains to the FIFO. Toward head. + afterIndex: + type: string + description: Pertains to the FIFO. Toward tail. pagination: type: object properties: @@ -206,6 +212,12 @@ paths: moveCount: type: string format: uint64 + beforeIndex: + type: string + description: Pertains to the FIFO. Toward head. + afterIndex: + type: string + description: Pertains to the FIFO. Toward tail. default: description: An unexpected error response. schema: @@ -247,6 +259,12 @@ paths: nextId: type: string format: uint64 + fifoHeadIndex: + type: string + description: Will contain the index of the game at the head. + fifoTailIndex: + type: string + description: Will contain the index of the game at the tail. default: description: An unexpected error response. schema: @@ -29764,6 +29782,12 @@ definitions: moveCount: type: string format: uint64 + beforeIndex: + type: string + description: Pertains to the FIFO. Toward head. + afterIndex: + type: string + description: Pertains to the FIFO. Toward tail. pagination: type: object properties: @@ -29812,6 +29836,12 @@ definitions: moveCount: type: string format: uint64 + beforeIndex: + type: string + description: Pertains to the FIFO. Toward head. + afterIndex: + type: string + description: Pertains to the FIFO. Toward tail. alice.checkers.checkers.QueryGetSystemInfoResponse: type: object properties: @@ -29821,6 +29851,12 @@ definitions: nextId: type: string format: uint64 + fifoHeadIndex: + type: string + description: Will contain the index of the game at the head. + fifoTailIndex: + type: string + description: Will contain the index of the game at the tail. alice.checkers.checkers.QueryParamsResponse: type: object properties: @@ -29848,12 +29884,24 @@ definitions: moveCount: type: string format: uint64 + beforeIndex: + type: string + description: Pertains to the FIFO. Toward head. + afterIndex: + type: string + description: Pertains to the FIFO. Toward tail. alice.checkers.checkers.SystemInfo: type: object properties: nextId: type: string format: uint64 + fifoHeadIndex: + type: string + description: Will contain the index of the game at the head. + fifoTailIndex: + type: string + description: Will contain the index of the game at the tail. cosmos.base.query.v1beta1.PageRequest: type: object properties: diff --git a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/index.ts b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/index.ts index d4d2be0..7e6e9a9 100755 --- a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/index.ts +++ b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/index.ts @@ -230,60 +230,60 @@ export default { }, - async sendMsgPlayMove({ rootGetters }, { value, fee = [], memo = '' }) { + async sendMsgCreateGame({ rootGetters }, { value, fee = [], memo = '' }) { try { const txClient=await initTxClient(rootGetters) - const msg = await txClient.msgPlayMove(value) + const msg = await txClient.msgCreateGame(value) const result = await txClient.signAndBroadcast([msg], {fee: { amount: fee, gas: "200000" }, memo}) return result } catch (e) { if (e == MissingWalletError) { - throw new Error('TxClient:MsgPlayMove:Init Could not initialize signing client. Wallet is required.') + throw new Error('TxClient:MsgCreateGame:Init Could not initialize signing client. Wallet is required.') }else{ - throw new Error('TxClient:MsgPlayMove:Send Could not broadcast Tx: '+ e.message) + throw new Error('TxClient:MsgCreateGame:Send Could not broadcast Tx: '+ e.message) } } }, - async sendMsgCreateGame({ rootGetters }, { value, fee = [], memo = '' }) { + async sendMsgPlayMove({ rootGetters }, { value, fee = [], memo = '' }) { try { const txClient=await initTxClient(rootGetters) - const msg = await txClient.msgCreateGame(value) + const msg = await txClient.msgPlayMove(value) const result = await txClient.signAndBroadcast([msg], {fee: { amount: fee, gas: "200000" }, memo}) return result } catch (e) { if (e == MissingWalletError) { - throw new Error('TxClient:MsgCreateGame:Init Could not initialize signing client. Wallet is required.') + throw new Error('TxClient:MsgPlayMove:Init Could not initialize signing client. Wallet is required.') }else{ - throw new Error('TxClient:MsgCreateGame:Send Could not broadcast Tx: '+ e.message) + throw new Error('TxClient:MsgPlayMove:Send Could not broadcast Tx: '+ e.message) } } }, - async MsgPlayMove({ rootGetters }, { value }) { + async MsgCreateGame({ rootGetters }, { value }) { try { const txClient=await initTxClient(rootGetters) - const msg = await txClient.msgPlayMove(value) + const msg = await txClient.msgCreateGame(value) return msg } catch (e) { if (e == MissingWalletError) { - throw new Error('TxClient:MsgPlayMove:Init Could not initialize signing client. Wallet is required.') + throw new Error('TxClient:MsgCreateGame:Init Could not initialize signing client. Wallet is required.') } else{ - throw new Error('TxClient:MsgPlayMove:Create Could not create message: ' + e.message) + throw new Error('TxClient:MsgCreateGame:Create Could not create message: ' + e.message) } } }, - async MsgCreateGame({ rootGetters }, { value }) { + async MsgPlayMove({ rootGetters }, { value }) { try { const txClient=await initTxClient(rootGetters) - const msg = await txClient.msgCreateGame(value) + const msg = await txClient.msgPlayMove(value) return msg } catch (e) { if (e == MissingWalletError) { - throw new Error('TxClient:MsgCreateGame:Init Could not initialize signing client. Wallet is required.') + throw new Error('TxClient:MsgPlayMove:Init Could not initialize signing client. Wallet is required.') } else{ - throw new Error('TxClient:MsgCreateGame:Create Could not create message: ' + e.message) + throw new Error('TxClient:MsgPlayMove:Create Could not create message: ' + e.message) } } }, diff --git a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/index.ts b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/index.ts index 8c870b0..5b17d0d 100755 --- a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/index.ts +++ b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/index.ts @@ -4,13 +4,13 @@ import { StdFee } from "@cosmjs/launchpad"; import { SigningStargateClient } from "@cosmjs/stargate"; import { Registry, OfflineSigner, EncodeObject, DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; import { Api } from "./rest"; -import { MsgPlayMove } from "./types/checkers/tx"; import { MsgCreateGame } from "./types/checkers/tx"; +import { MsgPlayMove } from "./types/checkers/tx"; const types = [ - ["/alice.checkers.checkers.MsgPlayMove", MsgPlayMove], ["/alice.checkers.checkers.MsgCreateGame", MsgCreateGame], + ["/alice.checkers.checkers.MsgPlayMove", MsgPlayMove], ]; export const MissingWalletError = new Error("wallet is required"); @@ -43,8 +43,8 @@ const txClient = async (wallet: OfflineSigner, { addr: addr }: TxClientOptions = return { signAndBroadcast: (msgs: EncodeObject[], { fee, memo }: SignAndBroadcastOptions = {fee: defaultFee, memo: ""}) => client.signAndBroadcast(address, msgs, fee,memo), - msgPlayMove: (data: MsgPlayMove): EncodeObject => ({ typeUrl: "/alice.checkers.checkers.MsgPlayMove", value: MsgPlayMove.fromPartial( data ) }), msgCreateGame: (data: MsgCreateGame): EncodeObject => ({ typeUrl: "/alice.checkers.checkers.MsgCreateGame", value: MsgCreateGame.fromPartial( data ) }), + msgPlayMove: (data: MsgPlayMove): EncodeObject => ({ typeUrl: "/alice.checkers.checkers.MsgPlayMove", value: MsgPlayMove.fromPartial( data ) }), }; }; diff --git a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/rest.ts b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/rest.ts index b86b87d..6ea67c2 100644 --- a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/rest.ts +++ b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/rest.ts @@ -69,11 +69,23 @@ export interface CheckersStoredGame { /** @format uint64 */ moveCount?: string; + + /** Pertains to the FIFO. Toward head. */ + beforeIndex?: string; + + /** Pertains to the FIFO. Toward tail. */ + afterIndex?: string; } export interface CheckersSystemInfo { /** @format uint64 */ nextId?: string; + + /** Will contain the index of the game at the head. */ + fifoHeadIndex?: string; + + /** Will contain the index of the game at the tail. */ + fifoTailIndex?: string; } export interface ProtobufAny { diff --git a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/stored_game.ts b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/stored_game.ts index 8f02883..168a5ad 100644 --- a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/stored_game.ts +++ b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/stored_game.ts @@ -13,6 +13,10 @@ export interface StoredGame { winner: string; deadline: string; moveCount: number; + /** Pertains to the FIFO. Toward head. */ + beforeIndex: string; + /** Pertains to the FIFO. Toward tail. */ + afterIndex: string; } const baseStoredGame: object = { @@ -24,6 +28,8 @@ const baseStoredGame: object = { winner: "", deadline: "", moveCount: 0, + beforeIndex: "", + afterIndex: "", }; export const StoredGame = { @@ -52,6 +58,12 @@ export const StoredGame = { if (message.moveCount !== 0) { writer.uint32(64).uint64(message.moveCount); } + if (message.beforeIndex !== "") { + writer.uint32(74).string(message.beforeIndex); + } + if (message.afterIndex !== "") { + writer.uint32(82).string(message.afterIndex); + } return writer; }, @@ -86,6 +98,12 @@ export const StoredGame = { case 8: message.moveCount = longToNumber(reader.uint64() as Long); break; + case 9: + message.beforeIndex = reader.string(); + break; + case 10: + message.afterIndex = reader.string(); + break; default: reader.skipType(tag & 7); break; @@ -136,6 +154,16 @@ export const StoredGame = { } else { message.moveCount = 0; } + if (object.beforeIndex !== undefined && object.beforeIndex !== null) { + message.beforeIndex = String(object.beforeIndex); + } else { + message.beforeIndex = ""; + } + if (object.afterIndex !== undefined && object.afterIndex !== null) { + message.afterIndex = String(object.afterIndex); + } else { + message.afterIndex = ""; + } return message; }, @@ -149,6 +177,9 @@ export const StoredGame = { message.winner !== undefined && (obj.winner = message.winner); message.deadline !== undefined && (obj.deadline = message.deadline); message.moveCount !== undefined && (obj.moveCount = message.moveCount); + message.beforeIndex !== undefined && + (obj.beforeIndex = message.beforeIndex); + message.afterIndex !== undefined && (obj.afterIndex = message.afterIndex); return obj; }, @@ -194,6 +225,16 @@ export const StoredGame = { } else { message.moveCount = 0; } + if (object.beforeIndex !== undefined && object.beforeIndex !== null) { + message.beforeIndex = object.beforeIndex; + } else { + message.beforeIndex = ""; + } + if (object.afterIndex !== undefined && object.afterIndex !== null) { + message.afterIndex = object.afterIndex; + } else { + message.afterIndex = ""; + } return message; }, }; diff --git a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/system_info.ts b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/system_info.ts index 42effcc..9080260 100644 --- a/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/system_info.ts +++ b/vue/src/store/generated/alice/checkers/alice.checkers.checkers/module/types/checkers/system_info.ts @@ -6,15 +6,29 @@ export const protobufPackage = "alice.checkers.checkers"; export interface SystemInfo { nextId: number; + /** Will contain the index of the game at the head. */ + fifoHeadIndex: string; + /** Will contain the index of the game at the tail. */ + fifoTailIndex: string; } -const baseSystemInfo: object = { nextId: 0 }; +const baseSystemInfo: object = { + nextId: 0, + fifoHeadIndex: "", + fifoTailIndex: "", +}; export const SystemInfo = { encode(message: SystemInfo, writer: Writer = Writer.create()): Writer { if (message.nextId !== 0) { writer.uint32(8).uint64(message.nextId); } + if (message.fifoHeadIndex !== "") { + writer.uint32(18).string(message.fifoHeadIndex); + } + if (message.fifoTailIndex !== "") { + writer.uint32(26).string(message.fifoTailIndex); + } return writer; }, @@ -28,6 +42,12 @@ export const SystemInfo = { case 1: message.nextId = longToNumber(reader.uint64() as Long); break; + case 2: + message.fifoHeadIndex = reader.string(); + break; + case 3: + message.fifoTailIndex = reader.string(); + break; default: reader.skipType(tag & 7); break; @@ -43,12 +63,26 @@ export const SystemInfo = { } else { message.nextId = 0; } + if (object.fifoHeadIndex !== undefined && object.fifoHeadIndex !== null) { + message.fifoHeadIndex = String(object.fifoHeadIndex); + } else { + message.fifoHeadIndex = ""; + } + if (object.fifoTailIndex !== undefined && object.fifoTailIndex !== null) { + message.fifoTailIndex = String(object.fifoTailIndex); + } else { + message.fifoTailIndex = ""; + } return message; }, toJSON(message: SystemInfo): unknown { const obj: any = {}; message.nextId !== undefined && (obj.nextId = message.nextId); + message.fifoHeadIndex !== undefined && + (obj.fifoHeadIndex = message.fifoHeadIndex); + message.fifoTailIndex !== undefined && + (obj.fifoTailIndex = message.fifoTailIndex); return obj; }, @@ -59,6 +93,16 @@ export const SystemInfo = { } else { message.nextId = 0; } + if (object.fifoHeadIndex !== undefined && object.fifoHeadIndex !== null) { + message.fifoHeadIndex = object.fifoHeadIndex; + } else { + message.fifoHeadIndex = ""; + } + if (object.fifoTailIndex !== undefined && object.fifoTailIndex !== null) { + message.fifoTailIndex = object.fifoTailIndex; + } else { + message.fifoTailIndex = ""; + } return message; }, }; diff --git a/x/checkers/genesis_test.go b/x/checkers/genesis_test.go index 21589ac..d90ee44 100644 --- a/x/checkers/genesis_test.go +++ b/x/checkers/genesis_test.go @@ -15,7 +15,9 @@ func TestGenesis(t *testing.T) { Params: types.DefaultParams(), SystemInfo: types.SystemInfo{ - NextId: 87, + NextId: 87, + FifoHeadIndex: "-1", + FifoTailIndex: "-1", }, StoredGameList: []types.StoredGame{ { diff --git a/x/checkers/keeper/end_block_server_game.go b/x/checkers/keeper/end_block_server_game.go new file mode 100644 index 0000000..e5235cf --- /dev/null +++ b/x/checkers/keeper/end_block_server_game.go @@ -0,0 +1,73 @@ +package keeper + +import ( + "context" + "fmt" + + "github.com/alice/checkers/x/checkers/rules" + "github.com/alice/checkers/x/checkers/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) ForfeitExpiredGames(goCtx context.Context) { + // TODO + ctx := sdk.UnwrapSDKContext(goCtx) + + opponents := map[string]string{ + rules.PieceStrings[rules.BLACK_PLAYER]: rules.PieceStrings[rules.RED_PLAYER], + rules.PieceStrings[rules.RED_PLAYER]: rules.PieceStrings[rules.BLACK_PLAYER], + } + systemInfo, found := k.GetSystemInfo(ctx) + if !found { + panic("SystemInfo not found") + } + + gameIndex := systemInfo.FifoHeadIndex + var storedGame types.StoredGame + + for { + // TODO + if gameIndex == types.NoFifoIndex { + break + } + storedGame, found = k.GetStoredGame(ctx, gameIndex) + if !found { + panic("Fifo head game not found " + systemInfo.FifoHeadIndex) + } + deadline, err := storedGame.GetDeadlineAsTime() + if err != nil { + panic(err) + } + + if deadline.Before(ctx.BlockTime()) { + // TODO: remove games with expired deadline + k.RemoveFromFifo(ctx, &storedGame, &systemInfo) + lastBoard := storedGame.Board + if storedGame.MoveCount <= 1 { + // No point in keeping a game that was never really played + k.RemoveStoredGame(ctx, gameIndex) + } else { + storedGame.Winner, found = opponents[storedGame.Turn] + if !found { + panic(fmt.Sprintf(types.ErrCannotFindWinnerByColor.Error(), storedGame.Turn)) + } + storedGame.Board = "" + k.SetStoredGame(ctx, storedGame) + } + ctx.EventManager().EmitEvent( + sdk.NewEvent(types.GameForfeitedEventType, + sdk.NewAttribute(types.GameForfeitedEventGameIndex, gameIndex), + sdk.NewAttribute(types.GameForfeitedEventWinner, storedGame.Winner), + sdk.NewAttribute(types.GameForfeitedEventBoard, lastBoard), + ), + ) + // Move along FIFO + gameIndex = systemInfo.FifoHeadIndex + } else { + // All other games after are active anyway + break + } + } + k.SetSystemInfo(ctx, systemInfo) + +} diff --git a/x/checkers/keeper/end_block_server_game_test.go b/x/checkers/keeper/end_block_server_game_test.go new file mode 100644 index 0000000..bd04bdb --- /dev/null +++ b/x/checkers/keeper/end_block_server_game_test.go @@ -0,0 +1,130 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/alice/checkers/x/checkers/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestForfeitUnplayed(t *testing.T) { + _, keeper, context := setupMsgServerWithOneGameForPlayMove(t) + ctx := sdk.UnwrapSDKContext(context) + game1, found := keeper.GetStoredGame(ctx, "1") + require.True(t, found) + game1.Deadline = types.FormatDeadline(ctx.BlockTime().Add(time.Duration(-1))) + keeper.SetStoredGame(ctx, game1) + keeper.ForfeitExpiredGames(context) + + _, found = keeper.GetStoredGame(ctx, "1") + require.False(t, found) + + systemInfo, found := keeper.GetSystemInfo(ctx) + require.True(t, found) + require.EqualValues(t, types.SystemInfo{ + NextId: 2, + FifoHeadIndex: "-1", + FifoTailIndex: "-1", + }, systemInfo) + events := sdk.StringifyEvents(ctx.EventManager().ABCIEvents()) + require.Len(t, events, 2) + event := events[0] + require.EqualValues(t, sdk.StringEvent{ + Type: "game-forfeited", + Attributes: []sdk.Attribute{ + {Key: "game-index", Value: "1"}, + {Key: "winner", Value: "*"}, + {Key: "board", Value: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*"}, + }, + }, event) +} + +func TestForfeitOlderUnplayed(t *testing.T) { + msgServer, keeper, context := setupMsgServerWithOneGameForPlayMove(t) + ctx := sdk.UnwrapSDKContext(context) + msgServer.CreateGame(context, &types.MsgCreateGame{ + Creator: bob, + Black: carol, + Red: alice, + }) + game1, found := keeper.GetStoredGame(ctx, "1") + require.True(t, found) + game1.Deadline = types.FormatDeadline(ctx.BlockTime().Add(time.Duration(-1))) + keeper.SetStoredGame(ctx, game1) + keeper.ForfeitExpiredGames(context) + + _, found = keeper.GetStoredGame(ctx, "1") + require.False(t, found) + + nextGame, found := keeper.GetSystemInfo(ctx) + require.True(t, found) + require.EqualValues(t, types.SystemInfo{ + NextId: 3, + FifoHeadIndex: "2", + FifoTailIndex: "2", + }, nextGame) + events := sdk.StringifyEvents(ctx.EventManager().ABCIEvents()) + require.Len(t, events, 2) + event := events[0] + require.EqualValues(t, sdk.StringEvent{ + Type: "game-forfeited", + Attributes: []sdk.Attribute{ + {Key: "game-index", Value: "1"}, + {Key: "winner", Value: "*"}, + {Key: "board", Value: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*"}, + }, + }, event) +} + +func TestForfeit2OldestUnplayedIn1Call(t *testing.T) { + msgServer, keeper, context := setupMsgServerWithOneGameForPlayMove(t) + ctx := sdk.UnwrapSDKContext(context) + msgServer.CreateGame(context, &types.MsgCreateGame{ + Creator: bob, + Black: carol, + Red: alice, + }) + msgServer.CreateGame(context, &types.MsgCreateGame{ + Creator: carol, + Black: alice, + Red: bob, + }) + game1, found := keeper.GetStoredGame(ctx, "1") + require.True(t, found) + game1.Deadline = types.FormatDeadline(ctx.BlockTime().Add(time.Duration(-1))) + keeper.SetStoredGame(ctx, game1) + game2, found := keeper.GetStoredGame(ctx, "2") + require.True(t, found) + game2.Deadline = types.FormatDeadline(ctx.BlockTime().Add(time.Duration(-1))) + keeper.SetStoredGame(ctx, game2) + keeper.ForfeitExpiredGames(context) + + _, found = keeper.GetStoredGame(ctx, "1") + require.False(t, found) + _, found = keeper.GetStoredGame(ctx, "2") + require.False(t, found) + + systemInfo, found := keeper.GetSystemInfo(ctx) + require.True(t, found) + require.EqualValues(t, types.SystemInfo{ + NextId: 4, + FifoHeadIndex: "3", + FifoTailIndex: "3", + }, systemInfo) + events := sdk.StringifyEvents(ctx.EventManager().ABCIEvents()) + require.Len(t, events, 2) + event := events[0] + require.EqualValues(t, sdk.StringEvent{ + Type: "game-forfeited", + Attributes: []sdk.Attribute{ + {Key: "game-index", Value: "1"}, + {Key: "winner", Value: "*"}, + {Key: "board", Value: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*"}, + {Key: "game-index", Value: "2"}, + {Key: "winner", Value: "*"}, + {Key: "board", Value: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*"}, + }, + }, event) +} diff --git a/x/checkers/keeper/msg_server_create_game.go b/x/checkers/keeper/msg_server_create_game.go index 168944b..b0423ef 100644 --- a/x/checkers/keeper/msg_server_create_game.go +++ b/x/checkers/keeper/msg_server_create_game.go @@ -20,21 +20,23 @@ func (k msgServer) CreateGame(goCtx context.Context, msg *types.MsgCreateGame) ( newGame := rules.New() storedGame := types.StoredGame{ - Index: newIndex, - Board: newGame.String(), - Turn: rules.PieceStrings[newGame.Turn], - Black: msg.Black, - Red: msg.Red, - Winner: rules.PieceStrings[rules.NO_PLAYER], - Deadline: types.FormatDeadline(types.GetNextDeadline(ctx)), - MoveCount: 0, + Index: newIndex, + Board: newGame.String(), + Turn: rules.PieceStrings[newGame.Turn], + Black: msg.Black, + Red: msg.Red, + Winner: rules.PieceStrings[rules.NO_PLAYER], + Deadline: types.FormatDeadline(types.GetNextDeadline(ctx)), + MoveCount: 0, + BeforeIndex: types.NoFifoIndex, + AfterIndex: types.NoFifoIndex, } err := storedGame.Validate() if err != nil { return nil, err } - + k.Keeper.SendToFifoTail(ctx, &storedGame, &systemInfo) k.Keeper.SetStoredGame(ctx, storedGame) systemInfo.NextId++ k.Keeper.SetSystemInfo(ctx, systemInfo) diff --git a/x/checkers/keeper/msg_server_create_game_fifo_test.go b/x/checkers/keeper/msg_server_create_game_fifo_test.go new file mode 100644 index 0000000..bb3453c --- /dev/null +++ b/x/checkers/keeper/msg_server_create_game_fifo_test.go @@ -0,0 +1,117 @@ +package keeper_test + +import ( + "testing" + + "github.com/alice/checkers/x/checkers/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestCreate3GamesHasSavedFifo(t *testing.T) { + msgSrvr, keeper, context := setupMsgServerCreateGame(t) + ctx := sdk.UnwrapSDKContext(context) + msgSrvr.CreateGame(context, &types.MsgCreateGame{ + Creator: alice, + Black: bob, + Red: carol, + }) + + // Second game + msgSrvr.CreateGame(context, &types.MsgCreateGame{ + Creator: bob, + Black: carol, + Red: alice, + }) + systemInfo2, found := keeper.GetSystemInfo(ctx) + require.True(t, found) + require.EqualValues(t, types.SystemInfo{ + NextId: 3, + FifoHeadIndex: "1", + FifoTailIndex: "2", + }, systemInfo2) + game1, found := keeper.GetStoredGame(ctx, "1") + require.True(t, found) + require.EqualValues(t, types.StoredGame{ + Index: "1", + Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", + Turn: "b", + Black: bob, + Red: carol, + Winner: "*", + Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + MoveCount: uint64(0), + BeforeIndex: "-1", + AfterIndex: "2", + }, game1) + game2, found := keeper.GetStoredGame(ctx, "2") + require.True(t, found) + require.EqualValues(t, types.StoredGame{ + Index: "2", + Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", + Turn: "b", + Black: carol, + Red: alice, + Winner: "*", + Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + MoveCount: uint64(0), + BeforeIndex: "1", + AfterIndex: "-1", + }, game2) + + // Third game + msgSrvr.CreateGame(context, &types.MsgCreateGame{ + Creator: carol, + Black: alice, + Red: bob, + }) + systemInfo3, found := keeper.GetSystemInfo(ctx) + require.True(t, found) + require.EqualValues(t, types.SystemInfo{ + NextId: 4, + FifoHeadIndex: "1", + FifoTailIndex: "3", + }, systemInfo3) + game1, found = keeper.GetStoredGame(ctx, "1") + require.True(t, found) + require.EqualValues(t, types.StoredGame{ + Index: "1", + Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", + Turn: "b", + Black: bob, + Red: carol, + Winner: "*", + Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + MoveCount: uint64(0), + BeforeIndex: "-1", + AfterIndex: "2", + }, game1) + game2, found = keeper.GetStoredGame(ctx, "2") + require.True(t, found) + require.EqualValues(t, types.StoredGame{ + Index: "2", + Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", + Turn: "b", + Black: carol, + Red: alice, + Winner: "*", + Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + MoveCount: uint64(0), + BeforeIndex: "1", + AfterIndex: "3", + }, game2) + game3, found := keeper.GetStoredGame(ctx, "3") + require.True(t, found) + require.EqualValues(t, types.StoredGame{ + Index: "3", + Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", + Turn: "b", + Black: alice, + Red: bob, + Winner: "*", + Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + MoveCount: uint64(0), + BeforeIndex: "2", + AfterIndex: "-1", + }, game3) +} diff --git a/x/checkers/keeper/msg_server_create_game_test.go b/x/checkers/keeper/msg_server_create_game_test.go index b956517..9b332f4 100644 --- a/x/checkers/keeper/msg_server_create_game_test.go +++ b/x/checkers/keeper/msg_server_create_game_test.go @@ -42,18 +42,20 @@ func TestCreate1GameHasSaved(t *testing.T) { systemInfo, found := keeper.GetSystemInfo(sdk.UnwrapSDKContext(context)) require.True(t, found) require.EqualValues(t, types.SystemInfo{ - NextId: 2, + NextId: 2, FifoHeadIndex: "1", FifoTailIndex: "1", }, systemInfo) game1, found1 := keeper.GetStoredGame(sdk.UnwrapSDKContext(context), "1") require.True(t, found1) require.EqualValues(t, types.StoredGame{ - Index: "1", - Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", - Turn: "b", - Black: bob, - Red: carol, - Winner: "*", - Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + Index: "1", + Board: "*b*b*b*b|b*b*b*b*|*b*b*b*b|********|********|r*r*r*r*|*r*r*r*r|r*r*r*r*", + Turn: "b", + Black: bob, + Red: carol, + Winner: "*", + Deadline: types.FormatDeadline(ctx.BlockTime().Add(types.MaxTurnDuration)), + BeforeIndex: "-1", + AfterIndex: "-1", }, game1) } diff --git a/x/checkers/keeper/msg_server_play_move.go b/x/checkers/keeper/msg_server_play_move.go index e9040ba..2d8ef54 100644 --- a/x/checkers/keeper/msg_server_play_move.go +++ b/x/checkers/keeper/msg_server_play_move.go @@ -55,17 +55,25 @@ func (k msgServer) PlayMove(goCtx context.Context, msg *types.MsgPlayMove) (*typ return nil, sdkerrors.Wrapf(types.ErrWrongMove, moveErr.Error()) } + systemInfo, found := k.Keeper.GetSystemInfo(ctx) + if !found { + panic("SystemInfo not found") + } + storedGame.Winner = rules.PieceStrings[game.Winner()] lastBoard := game.String() if storedGame.Winner == rules.PieceStrings[rules.NO_PLAYER] { storedGame.Board = lastBoard + k.Keeper.SendToFifoTail(ctx, &storedGame, &systemInfo) } else { storedGame.Board = "" + k.Keeper.RemoveFromFifo(ctx, &storedGame, &systemInfo) } storedGame.Turn = rules.PieceStrings[game.Turn] storedGame.Deadline = types.FormatDeadline(types.GetNextDeadline(ctx)) storedGame.MoveCount++ k.Keeper.SetStoredGame(ctx, storedGame) + k.Keeper.SetSystemInfo(ctx, systemInfo) ctx.EventManager().EmitEvent( sdk.NewEvent(types.MovePlayedEventType, diff --git a/x/checkers/keeper/msg_server_play_move_winner_test.go b/x/checkers/keeper/msg_server_play_move_winner_test.go index 28d4228..e1ac239 100644 --- a/x/checkers/keeper/msg_server_play_move_winner_test.go +++ b/x/checkers/keeper/msg_server_play_move_winner_test.go @@ -18,20 +18,22 @@ func TestPlayMoveUpToWinner(t *testing.T) { systemInfo, found := keeper.GetSystemInfo(ctx) require.True(t, found) require.EqualValues(t, types.SystemInfo{ - NextId: 2, + NextId: 2, FifoHeadIndex: "-1", FifoTailIndex: "-1", }, systemInfo) game, found := keeper.GetStoredGame(ctx, "1") require.True(t, found) require.EqualValues(t, types.StoredGame{ - Index: "1", - Board: "", - Turn: "b", - Black: bob, - Red: carol, - Winner: "b", - Deadline: "0001-01-02 00:00:00 +0000 UTC", - MoveCount: 40, + Index: "1", + Board: "", + Turn: "b", + Black: bob, + Red: carol, + Winner: "b", + Deadline: "0001-01-02 00:00:00 +0000 UTC", + MoveCount: 40, + AfterIndex: "-1", + BeforeIndex: "-1", }, game) events := sdk.StringifyEvents(ctx.EventManager().ABCIEvents()) require.Len(t, events, 2) diff --git a/x/checkers/keeper/stored_game_in_fifo.go b/x/checkers/keeper/stored_game_in_fifo.go new file mode 100644 index 0000000..0a62e8a --- /dev/null +++ b/x/checkers/keeper/stored_game_in_fifo.go @@ -0,0 +1,68 @@ +package keeper + +import ( + "github.com/alice/checkers/x/checkers/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) RemoveFromFifo(ctx sdk.Context, game *types.StoredGame, info *types.SystemInfo) { + // Does it have a predecessor? + if game.BeforeIndex != types.NoFifoIndex { + beforeElement, found := k.GetStoredGame(ctx, game.BeforeIndex) + if !found { + panic("Element before in Fifo was not found") + } + beforeElement.AfterIndex = game.AfterIndex + k.SetStoredGame(ctx, beforeElement) + if game.AfterIndex == types.NoFifoIndex { + info.FifoTailIndex = beforeElement.Index + } + // Is it at the FIFO head? + } else if info.FifoHeadIndex == game.Index { + info.FifoHeadIndex = game.AfterIndex + } + // Does it have a successor? + if game.AfterIndex != types.NoFifoIndex { + afterElement, found := k.GetStoredGame(ctx, game.AfterIndex) + if !found { + panic("Element after in Fifo was not found") + } + afterElement.BeforeIndex = game.BeforeIndex + k.SetStoredGame(ctx, afterElement) + if game.BeforeIndex == types.NoFifoIndex { + info.FifoHeadIndex = afterElement.Index + } + // Is it at the FIFO tail? + } else if info.FifoTailIndex == game.Index { + info.FifoTailIndex = game.BeforeIndex + } + game.BeforeIndex = types.NoFifoIndex + game.AfterIndex = types.NoFifoIndex +} + +func (k Keeper) SendToFifoTail(ctx sdk.Context, game *types.StoredGame, info *types.SystemInfo) { + if info.FifoHeadIndex == types.NoFifoIndex && info.FifoTailIndex == types.NoFifoIndex { + game.BeforeIndex = types.NoFifoIndex + game.AfterIndex = types.NoFifoIndex + info.FifoHeadIndex = game.Index + info.FifoTailIndex = game.Index + } else if info.FifoHeadIndex == types.NoFifoIndex || info.FifoTailIndex == types.NoFifoIndex { + panic("Fifo should have both head and tail or none") + } else if info.FifoTailIndex == game.Index { + // Nothing to do, already at tail + } else { + // Snip game out + k.RemoveFromFifo(ctx, game, info) + + // Now add to tail + currentTail, found := k.GetStoredGame(ctx, info.FifoTailIndex) + if !found { + panic("Current Fifo tail was not found") + } + currentTail.AfterIndex = game.Index + k.SetStoredGame(ctx, currentTail) + + game.BeforeIndex = currentTail.Index + info.FifoTailIndex = game.Index + } +} diff --git a/x/checkers/module.go b/x/checkers/module.go index 2bb7ab8..8192f68 100644 --- a/x/checkers/module.go +++ b/x/checkers/module.go @@ -170,6 +170,7 @@ func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} // EndBlock executes all ABCI EndBlock logic respective to the capability module. It // returns no validator updates. -func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + am.keeper.ForfeitExpiredGames(sdk.WrapSDKContext(ctx)) return []abci.ValidatorUpdate{} } diff --git a/x/checkers/types/errors.go b/x/checkers/types/errors.go index 3754d19..1354194 100644 --- a/x/checkers/types/errors.go +++ b/x/checkers/types/errors.go @@ -8,16 +8,17 @@ import ( // x/checkers module sentinel errors var ( - ErrInvalidBlack = sdkerrors.Register(ModuleName, 1100, "black address is invalid: %s") - ErrInvalidRed = sdkerrors.Register(ModuleName, 1101, "red address is invalid: %s") - ErrGameNotParseable = sdkerrors.Register(ModuleName, 1102, "game cannot be parsed") - ErrInvalidGameIndex = sdkerrors.Register(ModuleName, 1103, "game index is invalid") - ErrInvalidPositionIndex = sdkerrors.Register(ModuleName, 1104, "position index is invalid") - ErrMoveAbsent = sdkerrors.Register(ModuleName, 1105, "there is no move") - ErrGameNotFound = sdkerrors.Register(ModuleName, 1106, "game by id not found") - ErrCreatorNotPlayer = sdkerrors.Register(ModuleName, 1107, "message creator is not a player") - ErrNotPlayerTurn = sdkerrors.Register(ModuleName, 1108, "player tried to play out of turn") - ErrWrongMove = sdkerrors.Register(ModuleName, 1109, "wrong move") - ErrGameFinished = sdkerrors.Register(ModuleName, 1110, "game is already finished") - ErrInvalidDeadline = sdkerrors.Register(ModuleName, 1111, "deadline cannot be parsed: %s") + ErrInvalidBlack = sdkerrors.Register(ModuleName, 1100, "black address is invalid: %s") + ErrInvalidRed = sdkerrors.Register(ModuleName, 1101, "red address is invalid: %s") + ErrGameNotParseable = sdkerrors.Register(ModuleName, 1102, "game cannot be parsed") + ErrInvalidGameIndex = sdkerrors.Register(ModuleName, 1103, "game index is invalid") + ErrInvalidPositionIndex = sdkerrors.Register(ModuleName, 1104, "position index is invalid") + ErrMoveAbsent = sdkerrors.Register(ModuleName, 1105, "there is no move") + ErrGameNotFound = sdkerrors.Register(ModuleName, 1106, "game by id not found") + ErrCreatorNotPlayer = sdkerrors.Register(ModuleName, 1107, "message creator is not a player") + ErrNotPlayerTurn = sdkerrors.Register(ModuleName, 1108, "player tried to play out of turn") + ErrWrongMove = sdkerrors.Register(ModuleName, 1109, "wrong move") + ErrGameFinished = sdkerrors.Register(ModuleName, 1110, "game is already finished") + ErrInvalidDeadline = sdkerrors.Register(ModuleName, 1111, "deadline cannot be parsed: %s") + ErrCannotFindWinnerByColor = sdkerrors.Register(ModuleName, 1112, "cannot find winner by color: %s") ) diff --git a/x/checkers/types/genesis.go b/x/checkers/types/genesis.go index db2cc06..af94fac 100644 --- a/x/checkers/types/genesis.go +++ b/x/checkers/types/genesis.go @@ -11,7 +11,9 @@ const DefaultIndex uint64 = 1 func DefaultGenesis() *GenesisState { return &GenesisState{ SystemInfo: SystemInfo{ - NextId: uint64(DefaultIndex), + NextId: uint64(DefaultIndex), + FifoHeadIndex: NoFifoIndex, + FifoTailIndex: NoFifoIndex, }, StoredGameList: []StoredGame{}, // this line is used by starport scaffolding # genesis/types/default diff --git a/x/checkers/types/genesis_test.go b/x/checkers/types/genesis_test.go index 1085e2f..9a3e496 100644 --- a/x/checkers/types/genesis_test.go +++ b/x/checkers/types/genesis_test.go @@ -11,7 +11,7 @@ func TestDefaultGenesisState_ExpectedInitialNextId(t *testing.T) { require.EqualValues(t, &types.GenesisState{ StoredGameList: []types.StoredGame{}, - SystemInfo: types.SystemInfo{uint64(1)}, + SystemInfo: types.SystemInfo{uint64(1), "-1", "-1"}, }, types.DefaultGenesis()) } diff --git a/x/checkers/types/keys.go b/x/checkers/types/keys.go index f396b53..792fd81 100644 --- a/x/checkers/types/keys.go +++ b/x/checkers/types/keys.go @@ -46,10 +46,17 @@ const ( ) const ( - MaxTurnDuration = time.Duration(24 * 3_600 * 1000_000_000) // 1 day + MaxTurnDuration = time.Duration(5 * 60 * 1000_000_000) // 5 minutes DeadlineLayout = "2006-01-02 15:04:05.999999999 +0000 UTC" ) const ( NoFifoIndex = "-1" ) + +const ( + GameForfeitedEventType = "game-forfeited" + GameForfeitedEventGameIndex = "game-index" + GameForfeitedEventWinner = "winner" + GameForfeitedEventBoard = "board" +) diff --git a/x/checkers/types/stored_game.pb.go b/x/checkers/types/stored_game.pb.go index 014ca50..c87058d 100644 --- a/x/checkers/types/stored_game.pb.go +++ b/x/checkers/types/stored_game.pb.go @@ -23,14 +23,16 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type StoredGame struct { - Index string `protobuf:"bytes,1,opt,name=index,proto3" json:"index,omitempty"` - Board string `protobuf:"bytes,2,opt,name=board,proto3" json:"board,omitempty"` - Turn string `protobuf:"bytes,3,opt,name=turn,proto3" json:"turn,omitempty"` - Black string `protobuf:"bytes,4,opt,name=black,proto3" json:"black,omitempty"` - Red string `protobuf:"bytes,5,opt,name=red,proto3" json:"red,omitempty"` - Winner string `protobuf:"bytes,6,opt,name=winner,proto3" json:"winner,omitempty"` - Deadline string `protobuf:"bytes,7,opt,name=deadline,proto3" json:"deadline,omitempty"` - MoveCount uint64 `protobuf:"varint,8,opt,name=moveCount,proto3" json:"moveCount,omitempty"` + Index string `protobuf:"bytes,1,opt,name=index,proto3" json:"index,omitempty"` + Board string `protobuf:"bytes,2,opt,name=board,proto3" json:"board,omitempty"` + Turn string `protobuf:"bytes,3,opt,name=turn,proto3" json:"turn,omitempty"` + Black string `protobuf:"bytes,4,opt,name=black,proto3" json:"black,omitempty"` + Red string `protobuf:"bytes,5,opt,name=red,proto3" json:"red,omitempty"` + Winner string `protobuf:"bytes,6,opt,name=winner,proto3" json:"winner,omitempty"` + Deadline string `protobuf:"bytes,7,opt,name=deadline,proto3" json:"deadline,omitempty"` + MoveCount uint64 `protobuf:"varint,8,opt,name=moveCount,proto3" json:"moveCount,omitempty"` + BeforeIndex string `protobuf:"bytes,9,opt,name=beforeIndex,proto3" json:"beforeIndex,omitempty"` + AfterIndex string `protobuf:"bytes,10,opt,name=afterIndex,proto3" json:"afterIndex,omitempty"` } func (m *StoredGame) Reset() { *m = StoredGame{} } @@ -122,6 +124,20 @@ func (m *StoredGame) GetMoveCount() uint64 { return 0 } +func (m *StoredGame) GetBeforeIndex() string { + if m != nil { + return m.BeforeIndex + } + return "" +} + +func (m *StoredGame) GetAfterIndex() string { + if m != nil { + return m.AfterIndex + } + return "" +} + func init() { proto.RegisterType((*StoredGame)(nil), "alice.checkers.checkers.StoredGame") } @@ -129,23 +145,25 @@ func init() { func init() { proto.RegisterFile("checkers/stored_game.proto", fileDescriptor_8439c9c90688ff75) } var fileDescriptor_8439c9c90688ff75 = []byte{ - // 252 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0x31, 0x4e, 0xc3, 0x30, - 0x14, 0x86, 0x63, 0x9a, 0x86, 0xd6, 0x13, 0xb2, 0x10, 0x58, 0x15, 0xb2, 0x2a, 0xa6, 0x8a, 0x21, - 0x19, 0xb8, 0x01, 0x20, 0xb1, 0x97, 0x8d, 0x05, 0x39, 0xf6, 0x53, 0x6b, 0x35, 0xb1, 0x2b, 0xc7, - 0x81, 0x72, 0x0b, 0x4e, 0x85, 0x18, 0x3b, 0x32, 0xa2, 0xe4, 0x22, 0x28, 0xaf, 0x6d, 0xb2, 0xfd, - 0xdf, 0xf7, 0xbe, 0xe9, 0xd1, 0x99, 0x5a, 0x83, 0xda, 0x80, 0xaf, 0xb2, 0x2a, 0x38, 0x0f, 0xfa, - 0x6d, 0x25, 0x4b, 0x48, 0xb7, 0xde, 0x05, 0xc7, 0xae, 0x65, 0x61, 0x14, 0xa4, 0xa7, 0xa2, 0x1f, - 0xb7, 0xdf, 0x84, 0xd2, 0x17, 0xcc, 0x9f, 0x65, 0x09, 0xec, 0x92, 0x8e, 0x8d, 0xd5, 0xb0, 0xe3, - 0x64, 0x4e, 0x16, 0xd3, 0xe5, 0x01, 0x3a, 0x9b, 0x3b, 0xe9, 0x35, 0x3f, 0x3b, 0x58, 0x04, 0xc6, - 0x68, 0x1c, 0x6a, 0x6f, 0xf9, 0x08, 0x25, 0x6e, 0x2c, 0x0b, 0xa9, 0x36, 0x3c, 0x3e, 0x96, 0x1d, - 0xb0, 0x0b, 0x3a, 0xf2, 0xa0, 0xf9, 0x18, 0x5d, 0x37, 0xd9, 0x15, 0x4d, 0x3e, 0x8c, 0xb5, 0xe0, - 0x79, 0x82, 0xf2, 0x48, 0x6c, 0x46, 0x27, 0x1a, 0xa4, 0x2e, 0x8c, 0x05, 0x7e, 0x8e, 0x97, 0x9e, - 0xd9, 0x0d, 0x9d, 0x96, 0xee, 0x1d, 0x1e, 0x5d, 0x6d, 0x03, 0x9f, 0xcc, 0xc9, 0x22, 0x5e, 0x0e, - 0xe2, 0xe1, 0xe9, 0xa7, 0x11, 0x64, 0xdf, 0x08, 0xf2, 0xd7, 0x08, 0xf2, 0xd5, 0x8a, 0x68, 0xdf, - 0x8a, 0xe8, 0xb7, 0x15, 0xd1, 0xeb, 0xdd, 0xca, 0x84, 0x75, 0x9d, 0xa7, 0xca, 0x95, 0x19, 0xbe, - 0x21, 0xeb, 0x1f, 0xb5, 0x1b, 0x66, 0xf8, 0xdc, 0x42, 0x95, 0x27, 0xf8, 0xae, 0xfb, 0xff, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x73, 0xcc, 0x7d, 0x22, 0x4c, 0x01, 0x00, 0x00, + // 280 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0xbd, 0x4e, 0xc3, 0x30, + 0x14, 0x85, 0xeb, 0xfe, 0xd1, 0x5e, 0x16, 0x64, 0x21, 0xb0, 0x2a, 0x64, 0x55, 0x4c, 0x15, 0x43, + 0x32, 0xf0, 0x06, 0x80, 0x84, 0x58, 0xcb, 0xc6, 0x82, 0x9c, 0xf8, 0xb6, 0x8d, 0x9a, 0xd8, 0x95, + 0xe3, 0x40, 0x79, 0x03, 0x46, 0x1e, 0x8b, 0xb1, 0x23, 0x23, 0x4a, 0x5e, 0x04, 0xe5, 0xa6, 0xa4, + 0xdd, 0xce, 0xf9, 0xfc, 0x59, 0xba, 0x3a, 0x30, 0x89, 0x57, 0x18, 0xaf, 0xd1, 0xe5, 0x61, 0xee, + 0xad, 0x43, 0xfd, 0xba, 0x54, 0x19, 0x06, 0x1b, 0x67, 0xbd, 0xe5, 0x97, 0x2a, 0x4d, 0x62, 0x0c, + 0xfe, 0x8d, 0x36, 0x5c, 0x7f, 0x76, 0x01, 0x9e, 0x49, 0x7f, 0x54, 0x19, 0xf2, 0x73, 0x18, 0x24, + 0x46, 0xe3, 0x56, 0xb0, 0x29, 0x9b, 0x8d, 0xe7, 0x4d, 0xa9, 0x69, 0x64, 0x95, 0xd3, 0xa2, 0xdb, + 0x50, 0x2a, 0x9c, 0x43, 0xdf, 0x17, 0xce, 0x88, 0x1e, 0x41, 0xca, 0x64, 0xa6, 0x2a, 0x5e, 0x8b, + 0xfe, 0xde, 0xac, 0x0b, 0x3f, 0x83, 0x9e, 0x43, 0x2d, 0x06, 0xc4, 0xea, 0xc8, 0x2f, 0x60, 0xf8, + 0x9e, 0x18, 0x83, 0x4e, 0x0c, 0x09, 0xee, 0x1b, 0x9f, 0xc0, 0x48, 0xa3, 0xd2, 0x69, 0x62, 0x50, + 0x9c, 0xd0, 0x4b, 0xdb, 0xf9, 0x15, 0x8c, 0x33, 0xfb, 0x86, 0xf7, 0xb6, 0x30, 0x5e, 0x8c, 0xa6, + 0x6c, 0xd6, 0x9f, 0x1f, 0x00, 0x9f, 0xc2, 0x69, 0x84, 0x0b, 0xeb, 0xf0, 0x89, 0xee, 0x1f, 0xd3, + 0xe7, 0x63, 0xc4, 0x25, 0x80, 0x5a, 0x78, 0x74, 0x8d, 0x00, 0x24, 0x1c, 0x91, 0xbb, 0x87, 0xef, + 0x52, 0xb2, 0x5d, 0x29, 0xd9, 0x6f, 0x29, 0xd9, 0x57, 0x25, 0x3b, 0xbb, 0x4a, 0x76, 0x7e, 0x2a, + 0xd9, 0x79, 0xb9, 0x59, 0x26, 0x7e, 0x55, 0x44, 0x41, 0x6c, 0xb3, 0x90, 0x86, 0x0c, 0xdb, 0xa9, + 0xb7, 0x87, 0xe8, 0x3f, 0x36, 0x98, 0x47, 0x43, 0x1a, 0xfc, 0xf6, 0x2f, 0x00, 0x00, 0xff, 0xff, + 0x6e, 0x38, 0x3f, 0x3e, 0x8e, 0x01, 0x00, 0x00, } func (m *StoredGame) Marshal() (dAtA []byte, err error) { @@ -168,6 +186,20 @@ func (m *StoredGame) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AfterIndex) > 0 { + i -= len(m.AfterIndex) + copy(dAtA[i:], m.AfterIndex) + i = encodeVarintStoredGame(dAtA, i, uint64(len(m.AfterIndex))) + i-- + dAtA[i] = 0x52 + } + if len(m.BeforeIndex) > 0 { + i -= len(m.BeforeIndex) + copy(dAtA[i:], m.BeforeIndex) + i = encodeVarintStoredGame(dAtA, i, uint64(len(m.BeforeIndex))) + i-- + dAtA[i] = 0x4a + } if m.MoveCount != 0 { i = encodeVarintStoredGame(dAtA, i, uint64(m.MoveCount)) i-- @@ -273,6 +305,14 @@ func (m *StoredGame) Size() (n int) { if m.MoveCount != 0 { n += 1 + sovStoredGame(uint64(m.MoveCount)) } + l = len(m.BeforeIndex) + if l > 0 { + n += 1 + l + sovStoredGame(uint64(l)) + } + l = len(m.AfterIndex) + if l > 0 { + n += 1 + l + sovStoredGame(uint64(l)) + } return n } @@ -554,6 +594,70 @@ func (m *StoredGame) Unmarshal(dAtA []byte) error { break } } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BeforeIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStoredGame + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStoredGame + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStoredGame + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BeforeIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AfterIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStoredGame + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStoredGame + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStoredGame + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AfterIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStoredGame(dAtA[iNdEx:]) diff --git a/x/checkers/types/system_info.pb.go b/x/checkers/types/system_info.pb.go index 572ccb6..d6f4526 100644 --- a/x/checkers/types/system_info.pb.go +++ b/x/checkers/types/system_info.pb.go @@ -23,7 +23,9 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type SystemInfo struct { - NextId uint64 `protobuf:"varint,1,opt,name=nextId,proto3" json:"nextId,omitempty"` + NextId uint64 `protobuf:"varint,1,opt,name=nextId,proto3" json:"nextId,omitempty"` + FifoHeadIndex string `protobuf:"bytes,2,opt,name=fifoHeadIndex,proto3" json:"fifoHeadIndex,omitempty"` + FifoTailIndex string `protobuf:"bytes,3,opt,name=fifoTailIndex,proto3" json:"fifoTailIndex,omitempty"` } func (m *SystemInfo) Reset() { *m = SystemInfo{} } @@ -66,6 +68,20 @@ func (m *SystemInfo) GetNextId() uint64 { return 0 } +func (m *SystemInfo) GetFifoHeadIndex() string { + if m != nil { + return m.FifoHeadIndex + } + return "" +} + +func (m *SystemInfo) GetFifoTailIndex() string { + if m != nil { + return m.FifoTailIndex + } + return "" +} + func init() { proto.RegisterType((*SystemInfo)(nil), "alice.checkers.checkers.SystemInfo") } @@ -73,17 +89,19 @@ func init() { func init() { proto.RegisterFile("checkers/system_info.proto", fileDescriptor_1580c0dd88c0be2b) } var fileDescriptor_1580c0dd88c0be2b = []byte{ - // 152 bytes of a gzipped FileDescriptorProto + // 191 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xce, 0x48, 0x4d, 0xce, 0x4e, 0x2d, 0x2a, 0xd6, 0x2f, 0xae, 0x2c, 0x2e, 0x49, 0xcd, 0x8d, 0xcf, 0xcc, 0x4b, 0xcb, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4f, 0xcc, 0xc9, 0x4c, 0x4e, 0xd5, 0x83, 0xa9, - 0x80, 0x33, 0x94, 0x54, 0xb8, 0xb8, 0x82, 0xc1, 0xaa, 0x3d, 0xf3, 0xd2, 0xf2, 0x85, 0xc4, 0xb8, + 0x80, 0x33, 0x94, 0x0a, 0xb8, 0xb8, 0x82, 0xc1, 0xaa, 0x3d, 0xf3, 0xd2, 0xf2, 0x85, 0xc4, 0xb8, 0xd8, 0xf2, 0x52, 0x2b, 0x4a, 0x3c, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x58, 0x82, 0xa0, 0x3c, - 0x27, 0x97, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, - 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0x4a, 0xcf, 0x2c, - 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x07, 0xdb, 0xa1, 0x0f, 0x77, 0x45, 0x05, 0x82, - 0x59, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x76, 0x8b, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, - 0x46, 0xa6, 0xd1, 0xff, 0xa9, 0x00, 0x00, 0x00, + 0x21, 0x15, 0x2e, 0xde, 0xb4, 0xcc, 0xb4, 0x7c, 0x8f, 0xd4, 0xc4, 0x14, 0xcf, 0xbc, 0x94, 0xd4, + 0x0a, 0x09, 0x26, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x54, 0x41, 0x98, 0xaa, 0x90, 0xc4, 0xcc, 0x1c, + 0x88, 0x2a, 0x66, 0x84, 0x2a, 0xb8, 0xa0, 0x93, 0xcb, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, + 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, + 0xcb, 0x31, 0x44, 0x69, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x83, + 0xdd, 0xab, 0x0f, 0xf7, 0x51, 0x05, 0x82, 0x59, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0xf6, + 0x97, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x8a, 0x94, 0x2d, 0x63, 0xf5, 0x00, 0x00, 0x00, } func (m *SystemInfo) Marshal() (dAtA []byte, err error) { @@ -106,6 +124,20 @@ func (m *SystemInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.FifoTailIndex) > 0 { + i -= len(m.FifoTailIndex) + copy(dAtA[i:], m.FifoTailIndex) + i = encodeVarintSystemInfo(dAtA, i, uint64(len(m.FifoTailIndex))) + i-- + dAtA[i] = 0x1a + } + if len(m.FifoHeadIndex) > 0 { + i -= len(m.FifoHeadIndex) + copy(dAtA[i:], m.FifoHeadIndex) + i = encodeVarintSystemInfo(dAtA, i, uint64(len(m.FifoHeadIndex))) + i-- + dAtA[i] = 0x12 + } if m.NextId != 0 { i = encodeVarintSystemInfo(dAtA, i, uint64(m.NextId)) i-- @@ -134,6 +166,14 @@ func (m *SystemInfo) Size() (n int) { if m.NextId != 0 { n += 1 + sovSystemInfo(uint64(m.NextId)) } + l = len(m.FifoHeadIndex) + if l > 0 { + n += 1 + l + sovSystemInfo(uint64(l)) + } + l = len(m.FifoTailIndex) + if l > 0 { + n += 1 + l + sovSystemInfo(uint64(l)) + } return n } @@ -191,6 +231,70 @@ func (m *SystemInfo) Unmarshal(dAtA []byte) error { break } } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FifoHeadIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSystemInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSystemInfo + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSystemInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FifoHeadIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FifoTailIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSystemInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSystemInfo + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSystemInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FifoTailIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSystemInfo(dAtA[iNdEx:])