diff --git a/core/src/types/transactor_params.rs b/core/src/types/transactor_params.rs index 52872f38..3cedb48c 100644 --- a/core/src/types/transactor_params.rs +++ b/core/src/types/transactor_params.rs @@ -114,6 +114,7 @@ pub enum BroadcastFrame { game_addr: String, event: Event, timestamp: u64, + is_history: bool, }, // Arbitrary message Message { diff --git a/js/sdk-core/src/app-client.ts b/js/sdk-core/src/app-client.ts index c9f13264..a29a8ce3 100644 --- a/js/sdk-core/src/app-client.ts +++ b/js/sdk-core/src/app-client.ts @@ -21,7 +21,7 @@ import { SdkError } from './error'; import { EntryType, EntryTypeCash, GameAccount, GameBundle, IToken, PlayerProfile } from './accounts'; import { TxState } from './tx-state'; import { Client } from './client'; -import { Custom, GameEvent, ICustomEvent } from './events'; +import { Custom, GameEvent, ICustomEvent, Sync } from './events'; import { ProfileCache } from './profile-cache'; import { IStorage, getTtlCache, setTtlCache } from './storage'; import { DecryptionCache } from './decryption-cache'; @@ -31,7 +31,8 @@ const BUNDLE_CACHE_TTL = 3600 * 365; export type EventCallbackFunction = ( context: GameContextSnapshot, state: Uint8Array, - event: GameEvent | undefined + event: GameEvent | undefined, + isHistory: boolean, ) => void; export type MessageCallbackFunction = (message: Message) => void; export type TxStateCallbackFunction = (txState: TxState) => void; @@ -228,17 +229,17 @@ export class AppClient { return await this.#profileCaches.getProfile(addr); } - async invokeEventCallback(event: GameEvent | undefined) { + async invokeEventCallback(event: GameEvent | undefined, isHistory: boolean) { const snapshot = new GameContextSnapshot(this.#gameContext); const state = this.#gameContext.handlerState; - this.#onEvent(snapshot, state, event); + this.#onEvent(snapshot, state, event, isHistory); } async __initializeState(gameAccount: GameAccount): Promise { const initAccount = InitAccount.createFromGameAccount(gameAccount, this.gameContext.accessVersion, this.gameContext.settleVersion); console.log('Initialize state with', initAccount); await this.#handler.initState(this.#gameContext, initAccount); - await this.invokeEventCallback(undefined); + await this.invokeEventCallback(undefined, true); } async __getGameAccount(): Promise { @@ -308,12 +309,27 @@ export class AppClient { this.#gameContext.prepareForNextEvent(timestamp); try { let context = new GameContext(this.#gameContext); + if (event instanceof Sync) { + + while (true) { + let gameAccount = await this.#transport.getGameAccount(this.#gameAddr); + if (gameAccount === undefined) { + console.warn('Failed to get game account, will retry'); + await new Promise(r => setTimeout(r, 3000)); + continue; + } + for (const p of gameAccount.players) { + context.pushIdAddrPair(p.accessVersion, p.addr); + } + break; + } + } await this.#handler.handleEvent(context, event); this.#gameContext = context; } catch (err: any) { console.error(err); } - await this.invokeEventCallback(event); + await this.invokeEventCallback(event, frame.isHistory); } catch (e: any) { console.log("Game context in error:", this.#gameContext); throw e; @@ -406,7 +422,8 @@ export class AppClient { submitEvent(customEvent: ICustomEvent): Promise; async submitEvent(arg: ICustomEvent | Uint8Array): Promise { let raw = arg instanceof Uint8Array ? arg : arg.serialize(); - const event = new Custom({ sender: this.playerAddr, raw }); + const id = this.#gameContext.addrToId(this.playerAddr); + const event = new Custom({ sender: id, raw }); const connState = await this.#connection.submitEvent( new SubmitEventParams({ event, @@ -431,6 +448,15 @@ export class AppClient { } } + /** + * Parse the id to player's address. + * + * Throw an error when it fails. + */ + idToAddr(id: bigint): string { + return this.#gameContext.idToAddr(id) + } + /** * Get hidden knowledge by random id. The result contains both * public and private information. For performance reason, it's @@ -441,11 +467,6 @@ export class AppClient { return this.#decryptionCache.get(randomId) || new Map(); } - /** - * Close current event subscription. - */ - async close() {} - /** * Exit current game. */ diff --git a/js/sdk-core/src/client.ts b/js/sdk-core/src/client.ts index 7261ab7f..8f53db83 100644 --- a/js/sdk-core/src/client.ts +++ b/js/sdk-core/src/client.ts @@ -2,7 +2,7 @@ import { AttachGameParams, IConnection, SubmitEventParams } from './connection'; import { IEncryptor } from './encryptor'; import { SecretState } from './secret-state'; import { makeCustomEvent } from './events'; -import { GameContext } from './game-context'; +import { GameContext, IdAddrPair } from './game-context'; import { Id } from './types'; type OpIdent = @@ -32,6 +32,7 @@ export class Client { #addr: string; #opHist: OpIdent[]; #secretState: SecretState; + #id: bigint; constructor(addr: string, gameAddr: string, encryptor: IEncryptor, connection: IConnection) { this.#addr = addr; @@ -40,6 +41,7 @@ export class Client { this.#connection = connection; this.#opHist = new Array(); this.#secretState = new SecretState(encryptor); + this.#id = 0n; } async attachGame(): Promise { @@ -60,15 +62,6 @@ export class Client { ); } - async submitCustomEvent(customEvent: any): Promise { - const event = makeCustomEvent(this.#gameAddr, customEvent); - await this.#connection.submitEvent( - new SubmitEventParams({ - event, - }) - ); - } - async handleDecision(ctx: GameContext): Promise { return []; } diff --git a/js/sdk-core/src/connection.ts b/js/sdk-core/src/connection.ts index 8631dfaf..3364b662 100644 --- a/js/sdk-core/src/connection.ts +++ b/js/sdk-core/src/connection.ts @@ -90,6 +90,8 @@ export class BroadcastFrameEvent extends BroadcastFrame { event!: GameEvent; @field('u64') timestamp!: bigint; + @field('bool') + isHistory!: boolean; constructor(fields: any) { super(); Object.assign(this, fields); diff --git a/js/sdk-core/src/effect.ts b/js/sdk-core/src/effect.ts index c74c5ed3..43074454 100644 --- a/js/sdk-core/src/effect.ts +++ b/js/sdk-core/src/effect.ts @@ -105,8 +105,8 @@ export class Release { } export class ActionTimeout { - @field('string') - playerAddr!: string; + @field('u64') + playerId!: bigint; @field('u64') timeout!: bigint; constructor(fields: Fields) { @@ -115,8 +115,8 @@ export class ActionTimeout { } export class GamePlayer { - @field('string') - addr!: string; + @field('u64') + id!: bigint; @field('u16') position!: number; @field('u64') diff --git a/js/sdk-core/src/events.ts b/js/sdk-core/src/events.ts index 37216e39..53ccdcae 100644 --- a/js/sdk-core/src/events.ts +++ b/js/sdk-core/src/events.ts @@ -81,8 +81,8 @@ export abstract class GameEvent implements IEventKind { @variant(0) export class Custom extends GameEvent implements IEventKind { - @field('string') - sender!: string; + @field('u64') + sender!: bigint; @field('u8-array') raw!: Uint8Array; constructor(fields: EventFields) { @@ -94,7 +94,7 @@ export class Custom extends GameEvent implements IEventKind { } } -export function makeCustomEvent(sender: string, customEvent: ICustomEvent): Custom { +export function makeCustomEvent(sender: bigint, customEvent: ICustomEvent): Custom { return new Custom({ sender, raw: customEvent.serialize(), @@ -113,8 +113,8 @@ export class Ready extends GameEvent implements IEventKind { @variant(2) export class ShareSecrets extends GameEvent implements IEventKind { - @field('string') - sender!: string; + @field('u64') + sender!: bigint; @field(array(enums(SecretShare))) shares!: SecretShare[]; constructor(fields: EventFields) { @@ -128,8 +128,8 @@ export class ShareSecrets extends GameEvent implements IEventKind { @variant(3) export class OperationTimeout extends GameEvent implements IEventKind { - @field(array('string')) - addrs!: string[]; + @field(array('u64')) + ids!: bigint[]; constructor(fields: EventFields) { super(); Object.assign(this, fields); @@ -141,8 +141,8 @@ export class OperationTimeout extends GameEvent implements IEventKind { @variant(4) export class Mask extends GameEvent implements IEventKind { - @field('string') - sender!: string; + @field('u64') + sender!: bigint; @field('usize') randomId!: Id; @field(array('u8-array')) @@ -168,8 +168,8 @@ export class CiphertextAndDigest { @variant(5) export class Lock extends GameEvent implements IEventKind { - @field('string') - sender!: string; + @field('u64') + sender!: bigint; @field('usize') randomId!: Id; @field(array(struct(CiphertextAndDigest))) @@ -211,10 +211,8 @@ export class Sync extends GameEvent implements IEventKind { @variant(8) export class ServerLeave extends GameEvent implements IEventKind { - @field('string') - serverAddr!: string; - @field('string') - transactorAddr!: string; + @field('u64') + serverId!: bigint; constructor(fields: EventFields) { super(); Object.assign(this, fields); @@ -226,8 +224,8 @@ export class ServerLeave extends GameEvent implements IEventKind { @variant(9) export class Leave extends GameEvent implements IEventKind { - @field('string') - playerAddr!: string; + @field('u64') + playerId!: bigint; constructor(fields: EventFields) { super(); Object.assign(this, fields); @@ -262,8 +260,8 @@ export class WaitingTimeout extends GameEvent implements IEventKind { @variant(12) export class DrawRandomItems extends GameEvent implements IEventKind { - @field('string') - sender!: string; + @field('u64') + sender!: bigint; @field('usize') randomId!: Id; @field(array('usize')) @@ -289,8 +287,8 @@ export class DrawTimeout extends GameEvent implements IEventKind { @variant(14) export class ActionTimeout extends GameEvent implements IEventKind { - @field('string') - playerAddr!: string; + @field('u64') + playerId!: bigint; constructor(fields: EventFields) { super(); Object.assign(this, fields); @@ -302,8 +300,8 @@ export class ActionTimeout extends GameEvent implements IEventKind { @variant(15) export class AnswerDecision extends GameEvent implements IEventKind { - @field('string') - sender!: string; + @field('u64') + sender!: bigint; @field('usize') decisionId!: Id; @field('u8-array') diff --git a/js/sdk-core/src/game-context.ts b/js/sdk-core/src/game-context.ts index 087cc5d8..be1d54b1 100644 --- a/js/sdk-core/src/game-context.ts +++ b/js/sdk-core/src/game-context.ts @@ -39,6 +39,11 @@ export interface DispatchEvent { event: GameEvent; } +export interface IdAddrPair { + id: bigint; + addr: string; +} + export class GameContext { gameAddr: string; accessVersion: bigint; @@ -58,6 +63,7 @@ export class GameContext { checkpointAccessVersion: bigint; launchSubGames: LaunchSubGame[]; bridgeEvents: EmitBridgeEvent[]; + idAddrPairs: IdAddrPair[]; constructor(context: GameContext); constructor(gameAccount: GameAccount); @@ -82,6 +88,7 @@ export class GameContext { this.checkpointAccessVersion = context.checkpointAccessVersion; this.launchSubGames = context.launchSubGames; this.bridgeEvents = context.bridgeEvents; + this.idAddrPairs = context.idAddrPairs; } else { const gameAccount = gameAccountOrContext; const transactorAddr = gameAccount.transactorAddr; @@ -98,6 +105,14 @@ export class GameContext { }, })); + let idAddrPairs = []; + for (let x of gameAccount.players) { + idAddrPairs.push({ id: x.accessVersion, addr: x.addr }); + } + for (let x of gameAccount.servers) { + idAddrPairs.push({ id: x.accessVersion, addr: x.addr }); + } + this.gameAddr = gameAccount.addr; this.transactorAddr = transactorAddr; this.accessVersion = gameAccount.accessVersion; @@ -116,7 +131,28 @@ export class GameContext { this.checkpointAccessVersion = gameAccount.checkpointAccessVersion; this.launchSubGames = []; this.bridgeEvents = []; + this.idAddrPairs = idAddrPairs; + } + } + + idToAddr(id: bigint): string { + let found = this.idAddrPairs.find(x => x.id === id) + if (found === undefined) { + throw new Error('Cannot map id to address'); } + return found.addr + } + + addrToId(addr: string): bigint { + let found = this.idAddrPairs.find(x => x.addr === addr) + if (found === undefined) { + throw new Error('Cannot map address to id'); + } + return found.id + } + + pushIdAddrPair(id: bigint, addr: string) { + this.idAddrPairs.push({ id, addr }) } getNodeByAddress(addr: string): INode | undefined { @@ -141,9 +177,9 @@ export class GameContext { }; } - actionTimeout(playerAddr: string, timeout: bigint) { + actionTimeout(playerId: bigint, timeout: bigint) { this.dispatch = { - event: new ActionTimeout({ playerAddr }), + event: new ActionTimeout({ playerId }), timeout: this.timestamp + timeout, }; } @@ -283,13 +319,14 @@ export class GameContext { this.dispatchEventInstantly(new RandomnessReady({ randomId })); } else if (statusKind === 'locking' || statusKind === 'masking') { const addr = st.status.addr; + const id = this.addrToId(addr); if (noDispatch) { - this.dispatchEvent(new OperationTimeout({ addrs: [addr] }), OPERATION_TIMEOUT); + this.dispatchEvent(new OperationTimeout({ ids: [id] }), OPERATION_TIMEOUT); } } else if (statusKind === 'waiting-secrets') { if (noDispatch) { - const addrs = st.listOperatingAddrs(); - this.dispatchEvent(new OperationTimeout({ addrs }), OPERATION_TIMEOUT); + const ids = st.listOperatingAddrs().map(x => this.addrToId(x)); + this.dispatchEvent(new OperationTimeout({ ids }), OPERATION_TIMEOUT); } } } @@ -362,7 +399,7 @@ export class GameContext { } else if (effect.stopGame) { this.shutdownGame(); } else if (effect.actionTimeout !== undefined) { - this.actionTimeout(effect.actionTimeout.playerAddr, effect.actionTimeout.timeout); + this.actionTimeout(effect.actionTimeout.playerId, effect.actionTimeout.timeout); } else if (effect.waitTimeout !== undefined) { this.waitTimeout(effect.waitTimeout); } else if (effect.cancelDispatch) { diff --git a/js/sdk-core/src/handler.ts b/js/sdk-core/src/handler.ts index 229e799d..d0b87228 100644 --- a/js/sdk-core/src/handler.ts +++ b/js/sdk-core/src/handler.ts @@ -52,7 +52,7 @@ export class InitAccount { ): InitAccount { let { addr, players, data, checkpointAccessVersion } = gameAccount; const game_players = players.filter(p => p.accessVersion <= checkpointAccessVersion) - .map(p => new GamePlayer({ addr: p.addr, balance: p.balance, position: p.position })); + .map(p => new GamePlayer({ id: p.accessVersion, balance: p.balance, position: p.position })); return new InitAccount({ addr, data, @@ -130,7 +130,8 @@ export class Handler implements IHandler { async generalPreHandleEvent(context: GameContext, event: GameEvent, encryptor: IEncryptor) { if (event instanceof ShareSecrets) { const { sender, shares } = event; - context.addSharedSecrets(sender, shares); + const addr = context.idToAddr(sender); + context.addSharedSecrets(addr, shares); let randomIds: number[] = []; for (let randomState of context.randomStates) { if (randomState.status.kind === 'shared') { @@ -143,13 +144,16 @@ export class Handler implements IHandler { } } else if (event instanceof AnswerDecision) { const { decisionId, ciphertext, sender, digest } = event; - context.answerDecision(decisionId, sender, ciphertext, digest); + const addr = context.idToAddr(sender); + context.answerDecision(decisionId, addr, ciphertext, digest); } else if (event instanceof Mask) { const { sender, randomId, ciphertexts } = event; - context.randomizeAndMask(sender, randomId, ciphertexts); + const addr = context.idToAddr(sender); + context.randomizeAndMask(addr, randomId, ciphertexts); } else if (event instanceof Lock) { const { sender, randomId, ciphertextsAndDigests } = event; - context.lock(sender, randomId, ciphertextsAndDigests); + const addr = context.idToAddr(sender); + context.lock(addr, randomId, ciphertextsAndDigests); } else if (event instanceof Sync) { // No op here } else if (event instanceof Leave) { diff --git a/js/sdk-core/tests/effect.spec.ts b/js/sdk-core/tests/effect.spec.ts deleted file mode 100644 index 926d0511..00000000 --- a/js/sdk-core/tests/effect.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { assert } from 'chai'; -import { ActionTimeout, Ask, Assign, Effect, Release, Reveal, Settle, SettleAdd, SettleSub, Transfer } from '../src/effect'; -import { serialize } from '@race-foundation/borsh'; -import { ShuffledList } from '../src/random-state'; -import { CustomError, NoEnoughPlayers } from '../src/error'; - -describe('Test effect serialization 2', () => { - let effect = new Effect({ - actionTimeout: undefined, - waitTimeout: undefined, - startGame: false, - stopGame: false, - cancelDispatch: false, - timestamp: 1696586237379n, - currRandomId: 1, - currDecisionId: 1, - playersCount: 2, - serversCount: 1, - asks: [], - assigns: [], - reveals: [], - releases: [], - initRandomStates: [], - revealed: new Map(), - answered: new Map(), - isCheckpoint: false, - checkpoint: undefined, - settles: [], - handlerState: Uint8Array.from([0, 0, 0, 0, 0, 0, 0, 0, 16, 39, 0, 0, 0, 0, 0, 0, 32, 78, 0, 0, 0, 0, 0, 0, 32, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6]), - error: new CustomError({ message: "Failed to find a player for the next button" }), - allowExit: true, - transfers: [], - launchSubGames: [], - }); -}) - -describe('Test effect serialization', () => { - it('serialization', () => { - let effect = new Effect({ - actionTimeout: new ActionTimeout({ playerAddr: 'alice', timeout: 100n }), - waitTimeout: 200n, - startGame: true, - stopGame: true, - cancelDispatch: true, - timestamp: 300_000n, - currRandomId: 1, - currDecisionId: 1, - playersCount: 4, - serversCount: 4, - asks: [ - new Ask({ - playerAddr: 'bob', - }), - ], - assigns: [ - new Assign({ - randomId: 5, - playerAddr: 'bob', - indexes: [0, 1, 2], - }), - ], - reveals: [ - new Reveal({ - randomId: 6, - indexes: [0, 1, 2], - }), - ], - releases: [ - new Release({ - decisionId: 7, - }), - ], - initRandomStates: [ - new ShuffledList({ - options: ['a', 'b'], - }), - ], - revealed: new Map([[22, new Map([[11, 'B']])]]), - answered: new Map([[33, 'A']]), - isCheckpoint: false, - checkpoint: undefined, - settles: [ - new Settle({ - addr: 'alice', - op: new SettleAdd({ amount: 200n }), - }), - new Settle({ - addr: 'bob', - op: new SettleSub({ amount: 200n }), - }), - ], - handlerState: Uint8Array.of(1, 2, 3, 4), - error: new NoEnoughPlayers({}), - allowExit: true, - transfers: [new Transfer({ - slotId: 0, - amount: 100n - })], - launchSubGames: [], - }); - const data = serialize(effect); - const expected = Uint8Array.from([ - 1, 5, 0, 0, 0, 97, 108, 105, 99, 101, 100, 0, 0, 0, 0, 0, 0, 0, 1, 200, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 224, 147, 4, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 1, 0, 0, 0, 3, 0, 0, 0, 98, 111, 98, 1, - 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 98, 111, 98, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 97, 1, - 0, 0, 0, 98, 1, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 66, 1, 0, 0, 0, - 33, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 97, 108, 105, 99, 101, 0, 200, 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 98, 111, 98, 1, 200, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 1, 2, 3, 4, 1, 1, 1, 1, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]); - assert.deepEqual(data, expected); - }); -}); diff --git a/js/sdk-core/tests/events.spec.ts b/js/sdk-core/tests/events.spec.ts index 9ec773bc..ec3ecc84 100644 --- a/js/sdk-core/tests/events.spec.ts +++ b/js/sdk-core/tests/events.spec.ts @@ -24,6 +24,7 @@ import { import { assert } from 'chai'; import { deserialize, serialize, field } from '@race-foundation/borsh'; import { ServerJoin, PlayerJoin } from '../src/accounts'; +import { GamePlayer } from '../src/effect'; class TestCustom implements ICustomEvent { @field('u32') @@ -41,7 +42,7 @@ class TestCustom implements ICustomEvent { describe('Serialization', () => { it('Custom', () => { - let e = makeCustomEvent('alice', new TestCustom({ n: 100 })); + let e = makeCustomEvent(1n, new TestCustom({ n: 100 })); let data = serialize(e); let e1 = deserialize(GameEvent, data); assert.deepStrictEqual(e, e1); @@ -56,7 +57,7 @@ describe('Serialization', () => { it('ShareSecrets', () => { let e = new ShareSecrets({ - sender: 'alice', + sender: 1n, shares: [ new Random({ fromAddr: 'alice', @@ -78,14 +79,14 @@ describe('Serialization', () => { }); it('OperationTimeout', () => { - let e = new OperationTimeout({ addrs: ['alice', 'bob'] }); + let e = new OperationTimeout({ ids: [1n, 2n] }); let data = serialize(e); let e1 = deserialize(GameEvent, data); assert.deepStrictEqual(e1, e); }); it('Mask', () => { - let e = new Mask({ sender: 'alice', randomId: 1, ciphertexts: [Uint8Array.of(1, 2, 3)] }); + let e = new Mask({ sender: 1n, randomId: 1, ciphertexts: [Uint8Array.of(1, 2, 3)] }); let data = serialize(e); let e1 = deserialize(GameEvent, data); assert.deepStrictEqual(e1, e); @@ -93,7 +94,7 @@ describe('Serialization', () => { it('Lock', () => { let e = new Lock({ - sender: 'alice', + sender: 1n, randomId: 1, ciphertextsAndDigests: [ new CiphertextAndDigest({ @@ -119,24 +120,12 @@ describe('Serialization', () => { it('Sync', () => { let e = new Sync({ newPlayers: [ - new PlayerJoin({ - addr: 'alice', + new GamePlayer({ + id: 1n, position: 1, balance: 100n, - accessVersion: 1n, - verifyKey: 'key0', }), ], - newServers: [ - new ServerJoin({ - addr: 'foo', - endpoint: 'http://foo.bar', - accessVersion: 2n, - verifyKey: 'key1', - }), - ], - transactorAddr: 'foo', - accessVersion: 2n, }); let data = serialize(e); let e1 = deserialize(GameEvent, data); @@ -144,14 +133,14 @@ describe('Serialization', () => { }); it('ServerLeave', () => { - let e = new ServerLeave({ serverAddr: 'foo', transactorAddr: 'bar' }); + let e = new ServerLeave({ serverId: 2n }); let data = serialize(e); let e1 = deserialize(GameEvent, data); assert.deepStrictEqual(e1, e); }); it('Leave', () => { - let e = new Leave({ playerAddr: 'foo' }); + let e = new Leave({ playerId: 1n }); let data = serialize(e); let e1 = deserialize(GameEvent, data); assert.deepStrictEqual(e1, e); @@ -173,7 +162,7 @@ describe('Serialization', () => { it('DrawRandomItems', () => { let e = new DrawRandomItems({ - sender: 'alice', + sender: 1n, randomId: 1, indexes: [10, 20], }); @@ -199,10 +188,10 @@ describe('Serialization', () => { describe('Create custom event', () => { it('Create', () => { - let e = makeCustomEvent('addr', new TestCustom({ n: 1 })); + let e = makeCustomEvent(1n, new TestCustom({ n: 1 })); let e1 = new Custom({ - sender: 'addr', + sender: 1n, raw: Uint8Array.of(1, 0, 0, 0), }); diff --git a/transactor/src/component/broadcaster.rs b/transactor/src/component/broadcaster.rs index 8225cb4a..8e17c0e7 100644 --- a/transactor/src/component/broadcaster.rs +++ b/transactor/src/component/broadcaster.rs @@ -89,6 +89,7 @@ impl Broadcaster { game_addr: self.id.clone(), event: event.event.clone(), timestamp: event.timestamp, + is_history: true, }) } } @@ -190,6 +191,7 @@ impl Component for Broadcaster { game_addr: ctx.id.clone(), event, timestamp, + is_history: false, }); if let Err(e) = r {