public async Task TryConfirmAsync(DepositDetails deposit)
        {
            if (deposit.Confirmed || deposit.Rejected)
            {
                return;
            }

            var transactionHash = deposit.TransactionHash;
            var transaction     = await _blockchainBridge.GetTransactionAsync(deposit.TransactionHash);

            if (transaction is null)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Transaction was not found for hash: '{transactionHash}' for deposit: '{deposit.Id}' to be confirmed.");
                }
                return;
            }

            var headNumber = await _blockchainBridge.GetLatestBlockNumberAsync();

            var(confirmations, rejected) = await VerifyDepositConfirmationsAsync(deposit, transaction, headNumber);

            if (rejected)
            {
                deposit.Reject();
                await _depositRepository.UpdateAsync(deposit);

                await _consumerNotifier.SendDepositRejectedAsync(deposit.Id);

                return;
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Deposit: '{deposit.Id}' has {confirmations} confirmations (required at least {_requiredBlockConfirmations}) for transaction hash: '{transactionHash}' to be confirmed.");
            }
            var confirmed = confirmations >= _requiredBlockConfirmations;

            if (confirmed)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Deposit with id: '{deposit.Deposit.Id}' has been confirmed.");
                }
            }

            if (confirmations != deposit.Confirmations || confirmed)
            {
                deposit.SetConfirmations(confirmations);
                await _depositRepository.UpdateAsync(deposit);
            }

            await _consumerNotifier.SendDepositConfirmationsStatusAsync(deposit.Id, deposit.DataAsset.Name,
                                                                        confirmations, _requiredBlockConfirmations, deposit.ConfirmationTimestamp, confirmed);
        }
Example #2
0
        public async Task TryConfirmAsync(DepositDetails deposit)
        {
            if (deposit.Confirmed || deposit.Rejected || deposit.Cancelled || deposit.Transaction is null)
            {
                return;
            }

            NdmTransaction? transactionDetails  = null;
            TransactionInfo includedTransaction = deposit.Transactions.SingleOrDefault(t => t.State == TransactionState.Included);
            IOrderedEnumerable <TransactionInfo> pendingTransactions = deposit.Transactions
                                                                       .Where(t => t.State == TransactionState.Pending)
                                                                       .OrderBy(t => t.Timestamp);

            if (_logger.IsInfo)
            {
                _logger.Info($"Deposit: '{deposit.Id}' pending transactions: {string.Join(", ", pendingTransactions.Select(t => $"{t.Hash} [{t.Type}]"))}");
            }

            if (includedTransaction is null)
            {
                foreach (TransactionInfo transaction in pendingTransactions)
                {
                    Keccak?transactionHash = transaction.Hash;
                    if (transactionHash is null)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Transaction was not found for hash: '{null}' for deposit: '{deposit.Id}' to be confirmed.");
                        }
                        continue;
                    }

                    transactionDetails = await _blockchainBridge.GetTransactionAsync(transactionHash);

                    if (transactionDetails is null)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Transaction was not found for hash: '{transactionHash}' for deposit: '{deposit.Id}' to be confirmed.");
                        }
                        continue;
                    }

                    if (transactionDetails.IsPending)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Transaction with hash: '{transactionHash}' for deposit: '{deposit.Id}' is still pending.");
                        }
                        continue;
                    }

                    deposit.SetIncludedTransaction(transactionHash);
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Transaction with hash: '{transactionHash}', type: '{transaction.Type}' for deposit: '{deposit.Id}' was included into block: {transactionDetails.BlockNumber}.");
                    }
                    await _depositRepository.UpdateAsync(deposit);

                    includedTransaction = transaction;
                    break;
                }
            }
            else if (includedTransaction.Type == TransactionType.Cancellation)
            {
                return;
            }
            else
            {
                transactionDetails = includedTransaction.Hash == null ? null : await _blockchainBridge.GetTransactionAsync(includedTransaction.Hash);

                if (transactionDetails is null)
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"Transaction (set as included) was not found for hash: '{includedTransaction.Hash}' for deposit: '{deposit.Id}'.");
                    }
                    return;
                }
            }

            if (includedTransaction is null)
            {
                return;
            }

            long headNumber = await _blockchainBridge.GetLatestBlockNumberAsync();

            (uint confirmations, bool rejected) = await VerifyDepositConfirmationsAsync(deposit, transactionDetails !, headNumber);

            if (rejected)
            {
                deposit.Reject();
                await _depositRepository.UpdateAsync(deposit);

                await _consumerNotifier.SendDepositRejectedAsync(deposit.Id);

                return;
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Deposit: '{deposit.Id}' has {confirmations} confirmations (required at least {_requiredBlockConfirmations}) for transaction hash: '{includedTransaction.Hash}' to be confirmed.");
            }
            bool confirmed = confirmations >= _requiredBlockConfirmations;

            if (confirmed)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Deposit with id: '{deposit.Deposit.Id}' has been confirmed.");
                }
            }

            if (confirmations != deposit.Confirmations || confirmed)
            {
                deposit.SetConfirmations(confirmations);
                await _depositRepository.UpdateAsync(deposit);
            }

            await _consumerNotifier.SendDepositConfirmationsStatusAsync(deposit.Id, deposit.DataAsset.Name,
                                                                        confirmations, _requiredBlockConfirmations, deposit.ConfirmationTimestamp, confirmed);
        }
 public void can_set_rejected()
 {
     _depositDetails.Reject();
     Assert.IsTrue(_depositDetails.Rejected);
 }