public IActionResult BuildAndSendCallSmartContractTransaction([FromBody] BuildCallContractTransactionRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } BuildCallContractTransactionResponse response = this.smartContractTransactionService.BuildCallTx(request); if (!response.Success) { return(this.Json(response)); } Transaction transaction = this.network.CreateTransaction(response.Hex); if (!this.connectionManager.ConnectedPeers.Any()) { this.logger.LogTrace("(-)[NO_CONNECTED_PEERS]"); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Can't send transaction: sending transaction requires at least one connection!", string.Empty)); } this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); // Check if transaction was actually added to a mempool. TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (transactionBroadCastEntry?.State == Features.Wallet.Broadcasting.State.CantBroadcast) { this.logger.LogError("Exception occurred: {0}", transactionBroadCastEntry.ErrorMessage); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, transactionBroadCastEntry.ErrorMessage, "Transaction Exception")); } return(this.Json(response)); }
private async Task OnCrossChainTransactionFullySignedAsync(CrossChainTransferTransactionFullySigned @event) { if (this.ibdState.IsInitialBlockDownload() || !this.federationWalletManager.IsFederationWalletActive()) { this.logger.LogInformation("Federation wallet isn't active or in IBD. Not attempting to broadcast signed transactions."); return; } TxMempoolInfo txInfo = await this.mempoolManager.InfoAsync(@event.Transfer.PartialTransaction.GetHash()).ConfigureAwait(false); if (txInfo != null) { this.logger.LogDebug("Deposit ID '{0}' already in the mempool.", @event.Transfer.DepositTransactionId); return; } this.logger.LogDebug("Broadcasting deposit-id={0} a signed multisig transaction {1} to the network.", @event.Transfer.DepositTransactionId, @event.Transfer.PartialTransaction.GetHash()); await this.broadcasterManager.BroadcastTransactionAsync(@event.Transfer.PartialTransaction).ConfigureAwait(false); // Check if transaction was actually added to a mempool. TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(@event.Transfer.PartialTransaction.GetHash()); if (transactionBroadCastEntry?.TransactionBroadcastState == TransactionBroadcastState.CantBroadcast && !CrossChainTransferStore.IsMempoolErrorRecoverable(transactionBroadCastEntry.MempoolError)) { this.logger.LogWarning("Deposit ID '{0}' rejected due to '{1}'.", @event.Transfer.DepositTransactionId, transactionBroadCastEntry.ErrorMessage); this.store.RejectTransfer(@event.Transfer); } }
public static void UpdateMemoryPoolEntry(MemoryPoolEntry memoryPoolEntry, TransactionBroadcastEntry broadcastEntry) { var newState = broadcastEntry.State.ToBroadcastState(); var newErrorM = broadcastEntry.MempoolError.GetMemoryPoolError(); var newErrorC = broadcastEntry.MempoolError.GetMemoryPoolConsensusError(); var sb = new StringBuilder(); sb.AppendLine(); if (newState != memoryPoolEntry.BroadcastState) { sb.AppendLine($"BroadcastState {memoryPoolEntry.BroadcastState} -> {newState}"); } if (newErrorM != memoryPoolEntry.MemoryPoolError) { sb.AppendLine($"MemoryPoolError {memoryPoolEntry.MemoryPoolError} -> {newErrorM}"); } if (newErrorC != memoryPoolEntry.ConsensusError) { sb.AppendLine($"MemoryPoolError {memoryPoolEntry.ConsensusError} -> {newErrorC}"); } Log.Logger.LogInformation($"Updating Tracked tx {memoryPoolEntry.Transaction.HashTx}, changes: {sb}"); memoryPoolEntry.BroadcastState = newState; memoryPoolEntry.MemoryPoolError = newErrorM; memoryPoolEntry.ConsensusError = newErrorC; }
public IActionResult Call([FromBody] BuildCallContractTransactionRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } BuildCallContractTransactionResponse response = this.smartContractTransactionService.BuildCallTx(request); if (!response.Success) { return(this.BadRequest(this.Json(response))); } Transaction transaction = this.network.CreateTransaction(response.Hex); this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); // Check if transaction was actually added to a mempool. TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (transactionBroadCastEntry?.State == State.CantBroadcast) { this.logger.LogError("Exception occurred: {0}", transactionBroadCastEntry.ErrorMessage); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, transactionBroadCastEntry.ErrorMessage, "Transaction Exception")); } return(this.Json(response)); }
public bool TryGetFromBroadcastStore(uint256 transactionHash, out TransactionBroadcastEntry entry) { lock (BroadcastStoreLock) { var found = BroadcastStore.FirstOrDefault(x => x.TransactionId == transactionHash); entry = found; return(found is { });
public IActionResult SendTransaction([FromBody] SendTransactionRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { return(BuildErrorResponse(this.ModelState)); } if (!this.connectionManager.ConnectedPeers.Any()) { throw new WalletException("Can't send transaction: sending transaction requires at least one connection!"); } try { Transaction transaction = this.network.CreateTransaction(request.Hex); var model = new WalletSendTransactionModel { TransactionId = transaction.GetHash(), Outputs = new List <TransactionOutputModel>() }; foreach (TxOut output in transaction.Outputs) { bool isUnspendable = output.ScriptPubKey.IsUnspendable; string address = GetAddressFromScriptPubKey(output); model.Outputs.Add(new TransactionOutputModel { Address = address, Amount = output.Value, OpReturnData = isUnspendable ? Encoding.UTF8.GetString(output.ScriptPubKey.ToOps().Last().PushData) : null }); } this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (!string.IsNullOrEmpty(transactionBroadCastEntry?.ErrorMessage)) { this.logger.LogError("Exception occurred: {0}", transactionBroadCastEntry.ErrorMessage); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, transactionBroadCastEntry.ErrorMessage, "Transaction Exception")); } return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public TransactionBroadcastEntry GetTransaction(uint256 transactionHash) { TransactionBroadcastEntry txEntry = this.Broadcasts.FirstOrDefault(x => x.Transaction.GetHash() == transactionHash); if (txEntry == default(TransactionBroadcastEntry)) { return(null); } return(txEntry); }
public void AddOrUpdate(Transaction transaction, State state) { TransactionBroadcastEntry broadcastEntry = this.Broadcasts.FirstOrDefault(x => x.Transaction.GetHash() == transaction.GetHash()); if (broadcastEntry == null) { broadcastEntry = new TransactionBroadcastEntry(transaction, state); this.Broadcasts.Add(broadcastEntry); this.OnTransactionStateChanged(broadcastEntry); } else if (broadcastEntry.State != state) { broadcastEntry.State = state; this.OnTransactionStateChanged(broadcastEntry); } }
public bool TryAddToBroadcastStore(Transaction transaction, string nodeRemoteSocketEndpoint) { lock (BroadcastStoreLock) { if (BroadcastStore.Any(x => x.TransactionId == transaction.GetHash())) { return(false); } else { var entry = new TransactionBroadcastEntry(transaction, nodeRemoteSocketEndpoint); BroadcastStore.Add(entry); return(true); } } }
public bool TryGetFromBroadcastStore(uint256 transactionHash, out TransactionBroadcastEntry entry) { lock (BroadcastStoreLock) { var found = BroadcastStore.FirstOrDefault(x => x.TransactionId == transactionHash); entry = found; if (found is null) { return(false); } else { return(true); } } }
BroadcastState BroadCast(Transaction transaction) { if (!this.connectionManager.ConnectedPeers.Any()) { throw new X1WalletException(HttpStatusCode.BadRequest, "Can't send the transactions without connections."); } this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (transactionBroadCastEntry.State == State.CantBroadcast) { throw new X1WalletException(HttpStatusCode.InternalServerError, $"Can't send the transaction: {transactionBroadCastEntry.ErrorMessage}."); } return(transactionBroadCastEntry.State.ToBroadcastState()); }
private async Task <SignedMultisigTransactionBroadcastResultItem> BroadcastFullySignedTransfersAsync(ICrossChainTransfer crossChainTransfer) { var transferItem = new SignedMultisigTransactionBroadcastResultItem() { DepositId = crossChainTransfer.DepositTransactionId?.ToString(), TransactionId = crossChainTransfer.PartialTransaction.GetHash().ToString(), }; TxMempoolInfo txMempoolInfo = await this.mempoolManager.InfoAsync(crossChainTransfer.PartialTransaction.GetHash()).ConfigureAwait(false); if (txMempoolInfo != null) { this.logger.LogInformation("Deposit '{0}' already in the mempool.", crossChainTransfer.DepositTransactionId); transferItem.ItemMessage = $"Deposit '{crossChainTransfer.DepositTransactionId}' already in the mempool."; return(transferItem); } this.logger.LogInformation("Broadcasting deposit '{0}', a signed multisig transaction '{1'} to the network.", crossChainTransfer.DepositTransactionId, crossChainTransfer.PartialTransaction.GetHash()); await this.broadcasterManager.BroadcastTransactionAsync(crossChainTransfer.PartialTransaction).ConfigureAwait(false); // Check if transaction was added to a mempool. TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(crossChainTransfer.PartialTransaction.GetHash()); if (transactionBroadCastEntry == null) { return(transferItem); } // If there was no mempool error, then it safe to assume the transaction was broadcasted ok or already known. if (transactionBroadCastEntry.MempoolError == null) { return(transferItem); } if (transactionBroadCastEntry.TransactionBroadcastState == TransactionBroadcastState.CantBroadcast && !CrossChainTransferStore.IsMempoolErrorRecoverable(transactionBroadCastEntry.MempoolError)) { this.logger.LogWarning("Deposit '{0}' rejected: '{1}'.", crossChainTransfer.DepositTransactionId, transactionBroadCastEntry.ErrorMessage); this.crossChainTransferStore.RejectTransfer(crossChainTransfer); transferItem.ItemMessage = $"Deposit '{crossChainTransfer.DepositTransactionId}' rejected: '{transactionBroadCastEntry.ErrorMessage}'."; return(transferItem); } return(transferItem); }
void OnTransactionStateChanged(object sender, TransactionBroadcastEntry broadcastEntry) { if (broadcastEntry.State == State.CantBroadcast) { return; } try { this.WalletSemaphore.Wait(); base.TransactionBroadcastEntryChanged(broadcastEntry); } finally { this.WalletSemaphore.Release(); } }
protected void TransactionBroadcastEntryChanged(TransactionBroadcastEntry broadcastEntry) { var memoryPoolEntry = MemoryPoolService.GetMemoryPoolEntry(broadcastEntry.Transaction.GetHash(), this.metadata.MemoryPool.Entries); if (memoryPoolEntry == null) { TransactionMetadata walletTransaction = BlockService.AnalyzeTransaction(broadcastEntry.Transaction, int.MaxValue, this.metadata.Blocks.Values, GetOrAddAddress); if (walletTransaction != null) { var entry = MemoryPoolService.CreateMemoryPoolEntry(walletTransaction, broadcastEntry); this.metadata.MemoryPool.Entries.Add(entry); } } else { MemoryPoolService.UpdateMemoryPoolEntry(memoryPoolEntry, broadcastEntry); } SaveMetadata(); }
public async Task <IActionResult> BuildAndSendCallSmartContractTransactionAsync([FromBody] BuildCallContractTransactionRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } // Ignore this check if the node is running dev mode. if (this.nodeSettings.DevMode == null && !this.connectionManager.ConnectedPeers.Any()) { this.logger.LogTrace("(-)[NO_CONNECTED_PEERS]"); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Can't send transaction as the node requires at least one connection.", string.Empty)); } BuildCallContractTransactionResponse response = this.smartContractTransactionService.BuildCallTx(request); if (!response.Success) { return(this.Json(response)); } Transaction transaction = this.network.CreateTransaction(response.Hex); await this.broadcasterManager.BroadcastTransactionAsync(transaction); // Check if transaction was actually added to a mempool. TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (transactionBroadCastEntry?.TransactionBroadcastState == Features.Wallet.Broadcasting.TransactionBroadcastState.CantBroadcast) { this.logger.LogError("Exception occurred: {0}", transactionBroadCastEntry.ErrorMessage); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, transactionBroadCastEntry.ErrorMessage, "Transaction Exception")); } response.Message = $"Your CALL method {request.MethodName} transaction was successfully built and sent. Check the receipt using the transaction ID once it has been included in a new block."; return(this.Json(response)); }
private void BroadcasterManager_TransactionStateChanged(object sender, TransactionBroadcastEntry transactionEntry) { this.ProcessTransaction(transactionEntry.Transaction, null, null, transactionEntry.State == State.Propagated); }
public static MemoryPoolEntry CreateMemoryPoolEntry(TransactionMetadata walletTransaction, TransactionBroadcastEntry broadcastEntry) { var entry = new MemoryPoolEntry { Transaction = walletTransaction, TransactionTime = DateTime.UtcNow.ToUnixTime() }; if (broadcastEntry != null) { entry.BroadcastState = broadcastEntry.State.ToBroadcastState(); entry.MemoryPoolError = broadcastEntry.MempoolError.GetMemoryPoolError(); entry.ConsensusError = broadcastEntry.MempoolError.GetMemoryPoolError(); } return(entry); }
private void SetupTransactionWasBroadcast() { var cantBroadcastTransactionEntry = new TransactionBroadcastEntry(_transactionHelpers.CreateEmpty(), BroadcastState.Broadcasted, new MempoolError()); _broadcasterManager.Setup(callTo => callTo.GetTransaction(It.IsAny <uint256>())).Returns(cantBroadcastTransactionEntry); }
protected bool IsPropagated(Transaction transaction) { TransactionBroadcastEntry broadcastEntry = this.GetTransaction(transaction.GetHash()); return((broadcastEntry != null) && (broadcastEntry.State == State.Propagated)); }
public void OnTransactionStateChanged(TransactionBroadcastEntry entry) { this.TransactionStateChanged?.Invoke(this, entry); }