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."); } } }
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."); } }
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); }
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 }); } }
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); }
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); } }
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; } }
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; }
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); }
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); }
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); } }
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."); } }
private QueuedTransaction UpdateBucketIndex(QueuedTransaction queuedTransaction) { queuedTransaction.BucketIndex = Math.Abs(queuedTransaction.TransactionId.ToInt64() % _transactionOptions.PoolParallelismDegree); return(queuedTransaction); }