Beispiel #1
0
        public async Task <CommandHandlingResult> Handle(WaitForTransactionEndingCommand command,
                                                         IEventPublisher publisher)
        {
            var blockchainAsset = await _client.GetAssetAsync(command.GasBlockchainAssetId);

            var tx = await _client.TryGetBroadcastedSingleTransactionAsync(command.TransactionId, blockchainAsset);

            _chaosKitty.Meow(command.TransactionId);

            if (tx == null)
            {
                _log.Info("Blockchain API returned no transaction. Assuming, that it's already was cleared", command);

                // Transaction already has been forgotten, this means,
                // that process has been went further and no events should be generated here.

                return(CommandHandlingResult.Ok());
            }

            switch (tx.State)
            {
            case BroadcastedTransactionState.InProgress:

                return(CommandHandlingResult.Fail(_retryDelayProvider.WaitForTransactionRetryDelay));

            case BroadcastedTransactionState.Completed:

                publisher.PublishEvent(new GasClaimTransactionExecutedEvent
                {
                    TransactionId      = command.TransactionId,
                    Amount             = command.Amount,
                    BroadcastingBlock  = tx.Block,
                    BroadcastingMoment = tx.Timestamp,
                    TransactionHash    = tx.Hash
                });

                return(CommandHandlingResult.Ok());

            default:
                throw new ArgumentOutOfRangeException
                      (
                          nameof(tx.State),
                          $"Transaction state [{tx.State}] is not supported."
                      );
            }
        }
        public async Task <CommandHandlingResult> Handle(WaitForTransactionEndingCommand command, IEventPublisher publisher)
        {
            var apiClient = _apiClientProvider.Get(command.BlockchainType);

            // TODO: Cache it

            var blockchainAsset = await apiClient.GetAssetAsync(command.BlockchainAssetId);

            BaseBroadcastedTransaction transaction;

            OperationOutput[] transactionOutputs = null;

            if (command.Outputs.Length > 1)
            {
                var manyOutputsTransaction = await apiClient.TryGetBroadcastedTransactionWithManyOutputsAsync
                                             (
                    command.TransactionId,
                    blockchainAsset
                                             );

                transaction = manyOutputsTransaction;

                if (manyOutputsTransaction != null)
                {
                    transactionOutputs = manyOutputsTransaction.Outputs
                                         .Select(o => new OperationOutput
                    {
                        Address = o.ToAddress,
                        Amount  = o.Amount
                    })
                                         .ToArray();
                }
            }
            else if (command.Outputs.Length == 1)
            {
                var singleTransaction = await apiClient.TryGetBroadcastedSingleTransactionAsync
                                        (
                    command.TransactionId,
                    blockchainAsset
                                        );

                transaction = singleTransaction;

                if (singleTransaction != null)
                {
                    transactionOutputs = new[]
                    {
                        new OperationOutput
                        {
                            Address = command.Outputs.Single().Address,
                            Amount  = singleTransaction.Amount
                        }
                    };
                }
            }
            else
            {
                throw new InvalidOperationException("There should be at least one output");
            }

            if (transaction == null)
            {
                _log.Info("Blockchain API returned no transaction. Assuming, that it's already was cleared", command);

                // Transaction already has been forgotten, this means,
                // that process has been went further and no events should be generated here.

                return(CommandHandlingResult.Ok());
            }

            if (transactionOutputs == null)
            {
                throw new InvalidOperationException("Transaction outputs should be not null here");
            }

            switch (transaction.State)
            {
            case BroadcastedTransactionState.InProgress:

                return(CommandHandlingResult.Fail(_delayProvider.WaitForTransactionRetryDelay));

            case BroadcastedTransactionState.Completed:

                publisher.PublishEvent(new TransactionExecutionCompletedEvent
                {
                    OperationId        = command.OperationId,
                    TransactionId      = command.TransactionId,
                    TransactionNumber  = command.TransactionNumber,
                    TransactionHash    = transaction.Hash,
                    TransactionOutputs = transactionOutputs,
                    TransactionFee     = transaction.Fee,
                    TransactionBlock   = transaction.Block
                });

                return(CommandHandlingResult.Ok());

            case BroadcastedTransactionState.Failed:

                if (transaction.ErrorCode == BlockchainErrorCode.NotEnoughBalance ||
                    transaction.ErrorCode == BlockchainErrorCode.BuildingShouldBeRepeated)
                {
                    publisher.PublishEvent(new TransactionExecutionRepeatRequestedEvent
                    {
                        OperationId       = command.OperationId,
                        TransactionId     = command.TransactionId,
                        TransactionNumber = command.TransactionNumber,
                        ErrorCode         = transaction.ErrorCode.Value.MapToTransactionExecutionResult(),
                        Error             = transaction.Error
                    });
                }
                else
                {
                    publisher.PublishEvent(new TransactionExecutionFailedEvent
                    {
                        OperationId       = command.OperationId,
                        TransactionId     = command.TransactionId,
                        TransactionNumber = command.TransactionNumber,
                        ErrorCode         = transaction.ErrorCode?.MapToTransactionExecutionResult() ?? TransactionExecutionResult.UnknownError,
                        Error             = transaction.Error
                    });
                }

                return(CommandHandlingResult.Ok());

            default:
                throw new ArgumentOutOfRangeException
                      (
                          nameof(transaction.State),
                          $"Transaction state [{transaction.State}] is not supported."
                      );
            }
        }
Beispiel #3
0
 public async Task SendWaitForTransactionEndingCommand([FromBody] WaitForTransactionEndingCommand command)
 {
     _cqrsEngine.SendCommand(command, $"{CqrsModule.TransactionExecutor}.saga", CqrsModule.TransactionExecutor);
 }
Beispiel #4
0
 public async Task <ActionResult <IReadOnlyCollection <Guid> > > GetOperationsToRebuild([FromBody] WaitForTransactionEndingCommand command)
 {
     return(Ok(await _transactionsToRebuildRepository.GetAll()));
 }