/// <inheritdoc />
 public Task SaveStartRoundAsync(GameRoundId gameRoundId,
                                 EthereumNetwork network,
                                 AccountAddress createdByAccount,
                                 ContractAddress gameManagerContract,
                                 ContractAddress gameContract,
                                 Seed seedCommit,
                                 Seed seedReveal,
                                 TimeSpan roundDuration,
                                 TimeSpan bettingCloseDuration,
                                 TimeSpan roundTimeoutDuration,
                                 BlockNumber blockNumberCreated,
                                 TransactionHash transactionHash)
 {
     return(this._database.ExecuteAsync(storedProcedure: @"Games.GameRound_Insert",
                                        new
     {
         GameRoundId = gameRoundId,
         GameManagerContract = gameManagerContract,
         GameContract = gameContract,
         CreatedByAccount = createdByAccount,
         Network = network.Name,
         BlockNumberCreated = blockNumberCreated,
         SeedCommit = seedCommit,
         SeedReveal = seedReveal,
         BettingCloseDuration = bettingCloseDuration.TotalSeconds,
         RoundDuration = roundDuration.TotalSeconds,
         RoundTimeoutDuration = roundTimeoutDuration.TotalSeconds,
         TransactionHash = transactionHash
     }));
 }
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="gameRoundId">The game round id</param>
 /// <param name="createdByAccount">The account that created the game.</param>
 /// <param name="network">The network.</param>
 /// <param name="gameManagerContract">The game manager contract.</param>
 /// <param name="gameContract">The game network contract</param>
 /// <param name="seedCommit">The commit seed</param>
 /// <param name="seedReveal">The reveal seed</param>
 /// <param name="status">Status of game round</param>
 /// <param name="roundDuration">Round duration in seconds.</param>
 /// <param name="bettingCloseDuration">Duration of how long the betting close period is in seconds.</param>
 /// <param name="roundTimeoutDuration">Round timeout duration in seconds.</param>
 /// <param name="dateCreated">The date/time the round was created (transaction submitted)</param>
 /// <param name="dateUpdated">The date/time the round last updated</param>
 /// <param name="dateStarted">The date/time the round was activated (mined)</param>
 /// <param name="dateClosed">The date/time the round was closed.</param>
 /// <param name="blockNumberCreated">The block number the round was activated.</param>
 public GameRound(GameRoundId gameRoundId,
                  AccountAddress createdByAccount,
                  EthereumNetwork network,
                  ContractAddress gameManagerContract,
                  ContractAddress gameContract,
                  Seed seedCommit,
                  Seed seedReveal,
                  GameRoundStatus status,
                  TimeSpan roundDuration,
                  TimeSpan bettingCloseDuration,
                  TimeSpan roundTimeoutDuration,
                  DateTime dateCreated,
                  DateTime dateUpdated,
                  DateTime?dateStarted,
                  DateTime?dateClosed,
                  BlockNumber blockNumberCreated)
 {
     this.GameRoundId         = gameRoundId ?? throw new ArgumentNullException(nameof(gameRoundId));
     this.CreatedByAccount    = createdByAccount ?? throw new ArgumentNullException(nameof(createdByAccount));
     this.Network             = network ?? throw new ArgumentNullException(nameof(network));
     this.GameManagerContract = gameManagerContract ?? throw new ArgumentNullException(nameof(gameManagerContract));
     this.GameContract        = gameContract ?? throw new ArgumentNullException(nameof(gameContract));
     this.SeedCommit          = seedCommit ?? throw new ArgumentNullException(nameof(seedCommit));
     this.SeedReveal          = seedReveal ?? throw new ArgumentNullException(nameof(seedReveal));
     this.Status               = status;
     this.RoundDuration        = roundDuration;
     this.BettingCloseDuration = bettingCloseDuration;
     this.RoundTimeoutDuration = roundTimeoutDuration;
     this.DateCreated          = dateCreated;
     this.DateUpdated          = dateUpdated;
     this.DateStarted          = dateStarted;
     this.DateClosed           = dateClosed;
     this.BlockNumberCreated   = blockNumberCreated;
 }
Пример #3
0
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="gameRoundId">Game round id.</param>
 /// <param name="result">Game result.</param>
 /// <param name="history">Game History.</param>
 /// <param name="dateClosed">Date and time the game was closed.</param>
 public GameHistory(GameRoundId gameRoundId, byte[] result, byte[] history, DateTime dateClosed)
 {
     this.GameRoundId = gameRoundId ?? throw new ArgumentNullException(nameof(gameRoundId));
     this.Result      = result ?? throw new ArgumentNullException(nameof(result));
     this.History     = history ?? throw new ArgumentNullException(nameof(history));
     this.DateClosed  = dateClosed;
 }
Пример #4
0
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="gameRoundId">Game round id.</param>
 /// <param name="persistentGameDataId">The persistent game data id.</param>
 public StartGameRoundEventOutput([EventOutputParameter(ethereumDataType: "bytes32", order: 1, indexed: true)]
                                  GameRoundId gameRoundId,
                                  [EventOutputParameter(ethereumDataType: "bytes32", order: 2, indexed: true)]
                                  byte[] persistentGameDataId)
 {
     this.GameRoundId          = gameRoundId ?? throw new ArgumentNullException(nameof(gameRoundId));
     this.PersistentGameDataId = persistentGameDataId ?? throw new ArgumentNullException(nameof(persistentGameDataId));
 }
Пример #5
0
        public Task GameRoundBrokenAsync(EthereumNetwork network, GameRoundId gameRoundId)
        {
            this._logger.LogInformation($"{network.Name}: Game {gameRoundId} broken.");

            IEnumerable <IHub> hubs = this.GetAllHubs(network: network, includeLocalGroups: false, includeGlobalGroups: true);

            return(Task.WhenAll(hubs.Select(hub => hub.GameRoundBroken(roundId: gameRoundId, (int)GameRoundParameters.InterGameDelay.TotalSeconds))));
        }
Пример #6
0
        /// <inheritdoc />
        public Task BettingEndedAsync(EthereumNetwork network, GameRoundId gameRoundId, BlockNumber blockNumber, BlockNumber startBlockNumber)
        {
            this._logger.LogInformation($"{network.Name}: Game {gameRoundId} betting ended. Block number {blockNumber}");

            IEnumerable <IHub> hubs = this.GetAllHubs(network: network, includeLocalGroups: false, includeGlobalGroups: true);

            return(Task.WhenAll(hubs.Select(hub => hub.BettingEnded(roundId: gameRoundId, blockNumber: blockNumber))));
        }
Пример #7
0
        /// <inheritdoc />
        public Task GameRoundEndingAsync(EthereumNetwork network, GameRoundId gameRoundId, TransactionHash transactionHash, Seed seedReveal)
        {
            this._logger.LogInformation($"{network.Name}: Game {gameRoundId} ending. Txn hash {transactionHash}");

            IEnumerable <IHub> hubs = this.GetAllHubs(network: network, includeLocalGroups: false, includeGlobalGroups: true);

            return(Task.WhenAll(hubs.Select(hub => hub.GameRoundEnding(roundId: gameRoundId, transactionHash: transactionHash, seedReveal: seedReveal))));
        }
Пример #8
0
        /// <inheritdoc />
        public Task GameRoundEndedAsync(EthereumNetwork network, GameRoundId gameRoundId, BlockNumber blockNumber, BlockNumber startBlockNumber)
        {
            this._logger.LogInformation($"{network.Name}: Game {gameRoundId} ended. Block number {blockNumber}");

            IEnumerable <IHub> hubs = this.GetAllHubs(network: network, includeLocalGroups: false, includeGlobalGroups: true);

            return(Task.WhenAll(hubs.Select(hub => hub.GameRoundEnded(roundId: gameRoundId,
                                                                      blockNumber: blockNumber,
                                                                      (int)GameRoundParameters.InterGameDelay.TotalSeconds,
                                                                      startBlockNumber: startBlockNumber))));
        }
Пример #9
0
        /// <inheritdoc />
        public Task GameRoundStartedAsync(EthereumNetwork network, GameRoundId gameRoundId, int timeLeftInSeconds, BlockNumber blockNumber)
        {
            this._logger.LogInformation($"{network.Name}: Game {gameRoundId} started using . Block number: {blockNumber}. Remaining time: {timeLeftInSeconds}");

            IEnumerable <IHub> hubs = this.GetAllHubs(network: network, includeLocalGroups: false, includeGlobalGroups: true);

            return(Task.WhenAll(hubs.Select(hub => hub.GameRoundStarted(roundId: gameRoundId,
                                                                        timeLeftInSeconds: timeLeftInSeconds,
                                                                        blockNumber: blockNumber,
                                                                        (int)GameRoundParameters.InterGameDelay.TotalSeconds))));
        }
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="gameRoundId">Game round id.</param>
 /// <param name="persistentGameDataId">The persistent game data id.</param>
 /// <param name="entropyReveal">Entropy Reveal.</param>
 /// <param name="players">Player addresses.</param>
 /// <param name="winAmounts">Win amounts.</param>
 /// <param name="progressivePotWinLoss">Progressive Pot Win/Loss.</param>
 /// <param name="gameResult">Game Result (encoded).</param>
 /// <param name="historyToRecord">History to record (encoded).</param>
 public EndGameRoundEventOutput([EventOutputParameter(ethereumDataType: "bytes32", order: 1, indexed: true)]
                                GameRoundId gameRoundId,
                                [EventOutputParameter(ethereumDataType: "bytes32", order: 2, indexed: true)]
                                byte[] persistentGameDataId,
                                [EventOutputParameter(ethereumDataType: "bytes32", order: 3, indexed: false)]
                                Seed entropyReveal,
                                [EventOutputParameter(ethereumDataType: "address[]", order: 4, indexed: false)]
                                AccountAddress[] players,
                                [EventOutputParameter(ethereumDataType: "uint256[]", order: 5, indexed: false)]
                                DataTypes.Primitives.Token[] winAmounts,
                                [EventOutputParameter(ethereumDataType: "int256", order: 6, indexed: false)]
                                WinLoss progressivePotWinLoss,
                                [EventOutputParameter(ethereumDataType: "bytes", order: 7, indexed: false)]
                                byte[] gameResult,
                                [EventOutputParameter(ethereumDataType: "bytes", order: 8, indexed: false)]
                                byte[] historyToRecord)
 {
 /// <inheritdoc />
 public Task SaveEndRoundAsync(GameRoundId gameRoundId,
                               BlockNumber blockNumberCreated,
                               TransactionHash transactionHash,
                               WinAmount[] winAmounts,
                               WinLoss progressivePotWinLoss,
                               byte[] gameResult,
                               byte[] history)
 {
     return(this._database.ExecuteAsync(storedProcedure: @"Games.GameRound_Complete",
                                        new
     {
         GameRoundId = gameRoundId,
         BlockNumber = blockNumberCreated,
         TransactionHash = transactionHash,
         WinAmounts = this._winAmountTableBuilder.Build(winAmounts.Select(Convert)),
         ProgressiveWinLoss = progressivePotWinLoss,
         GameResult = gameResult,
         History = history
     }));
 }
Пример #12
0
        /// <inheritdoc />
        public async Task EndGameAsync(INetworkSigningAccount account, GameRoundId gameRoundId, INetworkBlockHeader networkBlockHeader, CancellationToken cancellationToken)
        {
            GameRound?game = await this._gameRoundDataManager.GetAsync(gameRoundId);

            if (game == null)
            {
                throw new NotSupportedException();
            }

            PendingTransaction pendingTransaction;

            try
            {
                EndGameRoundInput input = new(roundId : gameRoundId, entropyReveal : game.SeedReveal);

                pendingTransaction = await this._transactionService.SubmitAsync(account : account,
                                                                                transactionContext : new TransactionContext(contextType: @"GAMEROUND", gameRoundId.ToString()),
                                                                                input : input,
                                                                                cancellationToken : cancellationToken);
            }
            catch (TransactionWillAlwaysFailException exception)
            {
                this._logger.LogError(new EventId(exception.HResult), exception: exception, $"{account.Network.Name}: Failed to end game {gameRoundId}: {exception.Message}");

                await this._gameRoundDataManager.MarkAsBrokenAsync(gameRoundId : gameRoundId, closingBlockNumber : networkBlockHeader.Number, exceptionMessage : exception.Message);

                await this._gameStatisticsPublisher.GameRoundBrokenAsync(network : account.Network, gameRoundId : gameRoundId);

                return;
            }

            this._logger.LogInformation($"{account.Network.Name}: Ending game {gameRoundId}: tx {pendingTransaction.TransactionHash}");

            await this._gameRoundDataManager.BeginCompleteAsync(gameRoundId : gameRoundId, blockNumberCreated : networkBlockHeader.Number, transactionHash : pendingTransaction.TransactionHash);

            await this._gameStatisticsPublisher.GameRoundEndingAsync(network : account.Network,
                                                                     gameRoundId : gameRoundId,
                                                                     transactionHash : pendingTransaction.TransactionHash,
                                                                     seedReveal : game.SeedReveal);
        }
 /// <inheritdoc />
 public Task MarkAsBrokenAsync(GameRoundId gameRoundId, BlockNumber closingBlockNumber, string exceptionMessage)
 {
     return(this._database.ExecuteAsync(storedProcedure: @"Games.GameRound_MarkAsBroken", new { GameRoundId = gameRoundId, BlockNumber = closingBlockNumber, Reason = exceptionMessage }));
 }
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="roundId">Round Id.</param>
 /// <param name="entropyReveal">Entropy Reveal.</param>
 public EndGameRoundInput(GameRoundId roundId, Seed entropyReveal)
 {
     this.RoundId       = roundId ?? throw new ArgumentNullException(nameof(roundId));
     this.EntropyReveal = entropyReveal ?? throw new ArgumentNullException(nameof(entropyReveal));
 }
 /// <inheritdoc />
 public Task <GameRound?> GetAsync(GameRoundId gameRoundId)
 {
     return(this._database.QuerySingleOrDefaultAsync(builder: this._gameRoundBuilder, storedProcedure: @"Games.GameRound_GetById", new { GameRoundId = gameRoundId }));
 }
 /// <inheritdoc />
 public Task <IReadOnlyList <TransactionHash> > GetTransactionsAsync(GameRoundId gameRoundId, string functionName)
 {
     return(this._database.QueryAsync(builder: this._transactionHashBuilder, storedProcedure: "Games.GameRound_GetTransactions", new { GameRoundId = gameRoundId, FunctionName = functionName }));
 }
 /// <inheritdoc />
 public Task MarkAsBettingCompleteAsync(GameRoundId gameRoundId, BlockNumber blockNumber, TransactionHash transactionHash)
 {
     return(this._database.ExecuteAsync(storedProcedure: @"Games.GameRound_BettingComplete", new { GameRoundId = gameRoundId, BlockNumber = blockNumber, TransactionHash = transactionHash }));
 }
Пример #18
0
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="roundId">Round Id.</param>
 /// <param name="gameAddress">The Game Contract Address.</param>
 /// <param name="entropyCommit">Entropy Commit.</param>
 public StartGameRoundInput(GameRoundId roundId, ContractAddress gameAddress, Seed entropyCommit)
 {
     this.RoundId       = roundId ?? throw new ArgumentNullException(nameof(roundId));
     this.GameAddress   = gameAddress ?? throw new ArgumentNullException(nameof(gameAddress));
     this.EntropyCommit = entropyCommit ?? throw new ArgumentNullException(nameof(entropyCommit));
 }
 /// <inheritdoc />
 public Task ActivateAsync(GameRoundId gameRoundId, BlockNumber blockNumberCreated, DateTime activationTime, TransactionHash transactionHash)
 {
     return(this._database.ExecuteAsync(storedProcedure: @"Games.GameRound_Activate",
                                        new { GameRoundId = gameRoundId, BlockNumber = blockNumberCreated, DateStarted = activationTime, TransactionHash = transactionHash }));
 }
        private async Task <bool> AttemptToResolveEventAsync <TEventHandler, TEvent, TEventOutput>(INetworkBlockHeader blockHeader, GameRoundId gameRoundId, CancellationToken cancellationToken)
            where TEventHandler : IEventHandler <TEventOutput> where TEvent : Event <TEventOutput>, new() where TEventOutput : EventOutput
        {
            TEvent evt = this._contractInfo.Event <TEvent>();

            EventSignature eventSignature = this._eventSignatureFactory.Create(evt);

            IReadOnlyList <TransactionHash> transactionHashes = await this._gameRoundDataManager.GetTransactionsAsync(gameRoundId : gameRoundId, functionName : evt.Name);

            IReadOnlyList <IPendingNetworkTransaction> transactions =
                await this._transactionLoader.GetTransactionsAsync(network : blockHeader.Network, transactionHashes : transactionHashes, cancellationToken : cancellationToken);

            IReadOnlyList <NetworkTransactionReceipt> receipts =
                await this._transactionLoader.GetTransactionReceiptsAsync(network : blockHeader.Network, transactionHashes : transactionHashes, cancellationToken : cancellationToken);

            bool handled = false;

            foreach (NetworkTransactionReceipt?receipt in receipts)
            {
                IPendingNetworkTransaction transaction = transactions.First(tx => tx.TransactionHash == receipt.TransactionHash);

                IReadOnlyList <TransactionEventLogEntry> logs = receipts.SelectMany(r => r.Logs?.Where(l => l.Topics[0]
                                                                                                       .ToEventSignature() == eventSignature) ?? Array.Empty <TransactionEventLogEntry>())
                                                                .ToArray();

                IEventDispatcher ed = new EventDispatcher <TEventHandler, TEvent, TEventOutput>(contractInfo: this._contractInfo,
                                                                                                eventSignature: eventSignature,
                                                                                                eventHandlerFactory: this._eventHandlerFactory,
                                                                                                eventDataManager: this._eventDataManager,
                                                                                                eventDecoder: this._eventDecoder,
                                                                                                confirmationsReadinessChecker: this._confirmationsReadinessChecker,
                                                                                                logger: this._logger);

                handled |= await ed.DispatchAsync(network : blockHeader.Network,
                                                  logs : logs,
                                                  networkBlockHeader : blockHeader,
                                                  latestBlockNumberOnNetwork : blockHeader.Number,
                                                  isFresh : false,
                                                  gasUsed : receipt.GasUsed,
                                                  gasPrice : transaction.GasPrice,
                                                  retrievalStrategy : EventRetrievalStrategy.RISKY);
            }

            return(handled);
        }
Пример #21
0
 /// <summary>
 ///     Constructor.
 /// </summary>
 /// <param name="roundId">Round Id.</param>
 public StopBettingInput(GameRoundId roundId)
 {
     this.RoundId = roundId ?? throw new ArgumentNullException(nameof(roundId));
 }