Beispiel #1
0
        public async Task HandleTransactionsReceivedAsync(TransactionsReceivedEvent eventData)
        {
            if (_bestChainHash == Hash.Empty)
            {
                return;
            }

            foreach (var transaction in eventData.Transactions)
            {
                if (_processTransactionJobs.InputCount > _transactionOptions.PoolLimit)
                {
                    Logger.LogWarning("Already too many transaction processing job enqueued.");
                    break;
                }

                var queuedTransaction = new QueuedTransaction
                {
                    TransactionId = transaction.GetHash(),
                    Transaction   = transaction,
                    EnqueueTime   = TimestampHelper.GetUtcNow()
                };
                var sendResult = await _processTransactionJobs.SendAsync(queuedTransaction);

                if (!sendResult)
                {
                    Logger.LogWarning($"Process transaction:{queuedTransaction.TransactionId} failed.");
                }
            }
        }
Beispiel #2
0
        public async Task AddTransactionsAsync(IEnumerable <Transaction> transactions)
        {
            if (_bestChainHash == Hash.Empty)
            {
                return;
            }

            foreach (var transaction in transactions)
            {
                var transactionId     = transaction.GetHash();
                var queuedTransaction = new QueuedTransaction
                {
                    TransactionId = transactionId,
                    Transaction   = transaction,
                    EnqueueTime   = TimestampHelper.GetUtcNow()
                };
                var sendResult = await _processTransactionJobs.SendAsync(queuedTransaction);

                if (sendResult)
                {
                    continue;
                }
                await LocalEventBus.PublishAsync(new TransactionValidationStatusChangedEvent
                {
                    TransactionId           = transactionId,
                    TransactionResultStatus = TransactionResultStatus.NodeValidationFailed,
                    Error = "Failed to enter tx hub."
                });

                Logger.LogWarning($"Process transaction:{queuedTransaction.TransactionId} failed.");
            }
        }
Beispiel #3
0
        private async Task <bool> VerifyTransactionAcceptableAsync(QueuedTransaction queuedTransaction)
        {
            if (_allTransactions.ContainsKey(queuedTransaction.TransactionId))
            {
                return(false);
            }

            if (!queuedTransaction.Transaction.VerifyExpiration(_bestChainHeight))
            {
                await PublishTransactionNodeValidationFailedEventAsync(queuedTransaction.TransactionId,
                                                                       $"Transaction expired.Transaction RefBlockNumber is {queuedTransaction.Transaction.RefBlockNumber},best chain height is {_bestChainHeight}");

                return(false);
            }

            if (_allTransactions.Count >= _transactionOptions.PoolLimit)
            {
                await PublishTransactionNodeValidationFailedEventAsync(queuedTransaction.TransactionId,
                                                                       "Transaction Pool is full.");

                return(false);
            }

            if (await _blockchainService.HasTransactionAsync(queuedTransaction.TransactionId))
            {
                return(false);
            }

            return(true);
        }
Beispiel #4
0
        private async Task ProcessTransactionAsync(QueuedTransaction queuedTransaction)
        {
            if (_allTransactions.Count > _transactionOptions.PoolLimit)
            {
                return;
            }

            if (_allTransactions.ContainsKey(queuedTransaction.TransactionId))
            {
                return;
            }

            if (!queuedTransaction.Transaction.VerifyExpiration(_bestChainHeight))
            {
                return;
            }

            var validationResult =
                await _transactionValidationService.ValidateTransactionAsync(queuedTransaction.Transaction);

            if (!validationResult)
            {
                return;
            }

            var hasTransaction = await _blockchainService.HasTransactionAsync(queuedTransaction.TransactionId);

            if (hasTransaction)
            {
                return;
            }

            await _transactionManager.AddTransactionAsync(queuedTransaction.Transaction);

            var addSuccess = _allTransactions.TryAdd(queuedTransaction.TransactionId, queuedTransaction);

            if (!addSuccess)
            {
                return;
            }

            var prefix = await GetPrefixByHeightAsync(queuedTransaction.Transaction.RefBlockNumber, _bestChainHash);

            UpdateRefBlockStatus(queuedTransaction, prefix, _bestChainHeight);

            if (queuedTransaction.RefBlockStatus == RefBlockStatus.RefBlockExpired)
            {
                return;
            }

            if (queuedTransaction.RefBlockStatus == RefBlockStatus.RefBlockValid)
            {
                await LocalEventBus.PublishAsync(new TransactionAcceptedEvent()
                {
                    Transaction = queuedTransaction.Transaction
                });
            }
        }
Beispiel #5
0
        private static void AddToCollection(
            ConcurrentDictionary <long, ConcurrentDictionary <Hash, QueuedTransaction> > collection,
            QueuedTransaction receipt)
        {
            if (!collection.TryGetValue(receipt.Transaction.RefBlockNumber, out var receipts))
            {
                receipts = new ConcurrentDictionary <Hash, QueuedTransaction>();
                collection.TryAdd(receipt.Transaction.RefBlockNumber, receipts);
            }

            receipts.TryAdd(receipt.TransactionId, receipt);
        }
Beispiel #6
0
 private async Task <QueuedTransaction> ProcessQueuedTransactionAsync(QueuedTransaction queuedTransaction,
                                                                      Func <QueuedTransaction, Task <QueuedTransaction> > func)
 {
     try
     {
         return(await func(queuedTransaction));
     }
     catch (Exception e)
     {
         Logger.LogError(e,
                         $"Unacceptable transaction {queuedTransaction.TransactionId}. Func: {func?.Method.Name}");
         return(null);
     }
 }
Beispiel #7
0
        private void AddToCollection(QueuedTransaction queuedTransaction)
        {
            switch (queuedTransaction.RefBlockStatus)
            {
            case RefBlockStatus.RefBlockExpired:
                AddToCollection(_expiredByExpiryBlock, queuedTransaction);
                break;

            case RefBlockStatus.RefBlockInvalid:
                AddToCollection(_invalidatedByBlock, queuedTransaction);
                break;

            case RefBlockStatus.RefBlockValid:
                _validatedTransactions.TryAdd(queuedTransaction.TransactionId, queuedTransaction);
                break;
            }
        }
Beispiel #8
0
        private static void UpdateRefBlockStatus(QueuedTransaction queuedTransaction, ByteString prefix,
                                                 long bestChainHeight)
        {
            if (queuedTransaction.Transaction.GetExpiryBlockNumber() <= bestChainHeight)
            {
                queuedTransaction.RefBlockStatus = RefBlockStatus.RefBlockExpired;
                return;
            }

            if (queuedTransaction.Transaction.RefBlockPrefix == prefix)
            {
                queuedTransaction.RefBlockStatus = RefBlockStatus.RefBlockValid;
                return;
            }

            queuedTransaction.RefBlockStatus = RefBlockStatus.RefBlockInvalid;
        }
Beispiel #9
0
        private async Task <QueuedTransaction> UpdateQueuedTransactionRefBlockStatusAsync(
            QueuedTransaction queuedTransaction)
        {
            var prefix = await GetPrefixByHeightAsync(queuedTransaction.Transaction.RefBlockNumber, _bestChainHash);

            queuedTransaction.RefBlockStatus =
                CheckRefBlockStatus(queuedTransaction.Transaction, prefix, _bestChainHeight);

            if (queuedTransaction.RefBlockStatus == RefBlockStatus.RefBlockValid)
            {
                await LocalEventBus.PublishAsync(new TransactionAcceptedEvent
                {
                    Transaction = queuedTransaction.Transaction
                });
            }

            return(queuedTransaction);
        }
Beispiel #10
0
        private async Task <QueuedTransaction> AcceptTransactionAsync(QueuedTransaction queuedTransaction)
        {
            if (!await VerifyTransactionAcceptableAsync(queuedTransaction))
            {
                return(null);
            }

            var validationResult =
                await _transactionValidationService.ValidateTransactionWhileCollectingAsync(new ChainContext
            {
                BlockHash   = _bestChainHash,
                BlockHeight = _bestChainHeight
            }, queuedTransaction.Transaction);

            if (!validationResult)
            {
                Logger.LogDebug($"Transaction {queuedTransaction.TransactionId} validation failed.");
                return(null);
            }

            // double check
            var hasTransaction = await _blockchainService.HasTransactionAsync(queuedTransaction.TransactionId);

            if (hasTransaction)
            {
                return(null);
            }

            await _transactionManager.AddTransactionAsync(queuedTransaction.Transaction);

            var addSuccess = _allTransactions.TryAdd(queuedTransaction.TransactionId, queuedTransaction);

            if (addSuccess)
            {
                await UpdateQueuedTransactionRefBlockStatusAsync(queuedTransaction);

                return(queuedTransaction);
            }

            Logger.LogWarning($"Transaction {queuedTransaction.TransactionId} insert failed.");
            return(null);
        }
Beispiel #11
0
        public async Task HandleTransactionsReceivedAsync(TransactionsReceivedEvent eventData)
        {
            if (_bestChainHash == Hash.Empty)
            {
                return;
            }

            foreach (var transaction in eventData.Transactions)
            {
                if (_processTransactionJobs.InputCount > _transactionOptions.PoolLimit)
                {
                    break;
                }

                var queuedTransaction = new QueuedTransaction
                {
                    TransactionId = transaction.GetHash(),
                    Transaction   = transaction,
                    EnqueueTime   = TimestampHelper.GetUtcNow()
                };
                await _processTransactionJobs.SendAsync(queuedTransaction);
            }
        }
Beispiel #12
0
        private async Task ProcessTransactionAsync(QueuedTransaction queuedTransaction)
        {
            try
            {
                if (_allTransactions.Count > _transactionOptions.PoolLimit)
                {
                    return;
                }

                if (_allTransactions.ContainsKey(queuedTransaction.TransactionId))
                {
                    return;
                }

                if (!queuedTransaction.Transaction.VerifyExpiration(_bestChainHeight))
                {
                    Logger.LogWarning($"Transaction {queuedTransaction.TransactionId} already expired.");
                    return;
                }

                var validationResult =
                    await _transactionValidationService.ValidateTransactionWhileCollectingAsync(queuedTransaction
                                                                                                .Transaction);

                if (!validationResult)
                {
                    Logger.LogWarning($"Transaction {queuedTransaction.TransactionId} validation failed.");
                    return;
                }

                var hasTransaction = await _blockchainService.HasTransactionAsync(queuedTransaction.TransactionId);

                if (hasTransaction)
                {
                    return;
                }

                await _transactionManager.AddTransactionAsync(queuedTransaction.Transaction);

                var addSuccess = _allTransactions.TryAdd(queuedTransaction.TransactionId, queuedTransaction);
                if (!addSuccess)
                {
                    Logger.LogWarning($"Transaction {queuedTransaction.TransactionId} insert failed.");
                    return;
                }

                var prefix = await GetPrefixByHeightAsync(queuedTransaction.Transaction.RefBlockNumber, _bestChainHash);

                UpdateRefBlockStatus(queuedTransaction, prefix, _bestChainHeight);

                if (queuedTransaction.RefBlockStatus == RefBlockStatus.RefBlockExpired)
                {
                    return;
                }

                if (queuedTransaction.RefBlockStatus == RefBlockStatus.RefBlockValid)
                {
                    await LocalEventBus.PublishAsync(new TransactionAcceptedEvent()
                    {
                        Transaction = queuedTransaction.Transaction
                    });
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Process transaction failed.");
            }
        }
Beispiel #13
0
 private QueuedTransaction UpdateBucketIndex(QueuedTransaction queuedTransaction)
 {
     queuedTransaction.BucketIndex =
         Math.Abs(queuedTransaction.TransactionId.ToInt64() % _transactionOptions.PoolParallelismDegree);
     return(queuedTransaction);
 }