public async Task <ActionResult> Broadcast( [FromBody] BroadcastTransactionRequest request) { var broadcastResult = await _transactionService.BroadcastTransactionAsync ( transactionId : request.OperationId, signedTxData : request.SignedTransaction ); if (broadcastResult is BroadcastTransactionResult.TransactionHash) { return(Ok()); } else if (broadcastResult is BroadcastTransactionResult.Error error) { switch (error.Type) { case BroadcastTransactionError.AmountIsTooSmall: return(BadRequest( BlockchainErrorResponse.FromKnownError( BlockchainErrorCode.AmountIsTooSmall))); case BroadcastTransactionError.BalanceIsNotEnough: return(BadRequest( BlockchainErrorResponse.FromKnownError( BlockchainErrorCode.NotEnoughBalance))); case BroadcastTransactionError.TransactionHasBeenBroadcasted: return(Conflict( BlockchainErrorResponse.FromUnknownError ($"Transaction with specified id [{request.OperationId}] has already been broadcasted."))); case BroadcastTransactionError.TransactionHasBeenDeleted: return(Conflict( BlockchainErrorResponse.FromUnknownError ($"Transaction with specified id [{request.OperationId}] has already been deleted."))); case BroadcastTransactionError.TransactionShouldBeRebuilt: return(BadRequest( BlockchainErrorResponse.FromKnownError( BlockchainErrorCode.BuildingShouldBeRepeated))); case BroadcastTransactionError.OperationHasNotBeenFound: return(NoContent()); default: throw new ArgumentOutOfRangeException(); } } else { throw new NotSupportedException( $"{nameof(_transactionService.BroadcastTransactionAsync)} returned unsupported result."); } }
public async Task <IActionResult> Broadcast([FromBody] BroadcastTransactionRequest request) { try { await _transactionBroadcaster.BroadcastAsync(request); } catch (TransactionBroadcastingException ex) { var errorResponse = BlockchainErrorResponse.CreateFromCode(ex.Error, ex.Message); return(BadRequest(errorResponse)); } return(Ok()); }
private bool SetBalanceWIthManyOutputs(List <WalletCreationResponse> wallets) { var run = blockchainApi.Capabilities.GetCapabilities().GetResponseObject().AreManyOutputsSupported; if (run == null || !run.Value) { return(false); } List <TransactionOutputContract> transactions = new List <TransactionOutputContract>(); wallets.ForEach(w => transactions.Add(new TransactionOutputContract() { Amount = AMOUT_WITH_FEE, ToAddress = w.PublicAddress })); var request = new BuildTransactionWithManyOutputsRequest() { AssetId = ASSET_ID, OperationId = Guid.NewGuid(), FromAddress = EXTERNAL_WALLET, Outputs = transactions }; wallets.ForEach(w => blockchainApi.Balances.PostBalances(w.PublicAddress)); var response = blockchainApi.Operations.PostTransactionsManyOutputs(request); response.Validate.StatusCode(HttpStatusCode.OK); var signResponse = blockchainSign.PostSign(new SignRequest() { TransactionContext = response.GetResponseObject().TransactionContext, PrivateKeys = new List <string>() { EXTERNAL_WALLET_KEY } }); var broadcastRequset = new BroadcastTransactionRequest() { OperationId = request.OperationId, SignedTransaction = signResponse.GetResponseObject().SignedTransaction }; var broadcatedResponse = blockchainApi.Operations.PostTransactionsBroadcast(broadcastRequset); WaitForBalance(wallets[0].PublicAddress); return(true); }
public async Task BroadcastAsync(BroadcastTransactionRequest request) { // TODO: broadcast transaction // // Throw: // - Lykke.Bil2.Contract.Common.Exceptions.RequestValidationException: // if a transaction can’t be broadcasted with the given parameters. // It should be guaranteed that the transaction is not included and will not be // included to the any blockchain block. // // - Lykke.Bil2.Sdk.TransactionsExecutor.Exceptions.TransactionBroadcastingException: // if a transaction cannot be broadcasted and the reason can be // mapped to the Lykke.Bil2.Contract.TransactionsExecutor.TransactionBroadcastingError. // It should be guaranteed that the transaction is not included and will not be // included to the any blockchain block. // // - System.Exception: // if there are any other errors. // It can be thrown without guarantee that transaction was broadcasted to the // blockchain or not. Request will be not retried automatically. // // For example // // SignedTransaction signed; // // try // { // signed = JsonConvert.DeserializeObject<SignedTransaction>(request.SignedTransaction.DecodeToString()); // } // catch (JsonException ex) // { // throw new RequestValidationException("Failed to deserialize signed transaction", request.SignedTransaction, ex, nameof(request.SignedTransaction)); // } // // var result = await BcnApi.Send(signed); // // switch (result) // { // case 100: // throw new TransactionBroadcastingException(TransactionBroadcastingError.RebuildRequired, "Transaction expired"); // // case 200: // throw new TransactionBroadcastingException(TransactionBroadcastingError.RetryLater, "Node is busy"); // } throw new System.NotImplementedException(); }
public async Task <IActionResult> Broadcast([FromBody] BroadcastTransactionRequest request) { try { // Broadcast the signed transaction await _txBroadcastService.Broadcast(request.OperationId, request.SignedTransaction); Response.StatusCode = (int)HttpStatusCode.OK; return(Json(new { errorMessage = "" })); } catch (BusinessException ex) when(ex.Reason == ErrorReason.DuplicateRecord) { // If this operationid was already broadcast, return 409 conflict. return(await GenericErrorResponse(ex, request.OperationId, HttpStatusCode.Conflict)); } }
public async Task <IActionResult> BroadcastTransaction([FromBody] BroadcastTransactionRequest request) { if (request == null) { return(BadRequest(ErrorResponse.Create("Unable to deserialize request"))); } var aggregate = await _operationRepository.GetOrDefault(request.OperationId); if (aggregate == null) { return(BadRequest(ErrorResponse.Create($"Operation {request.OperationId} not found"))); } Transaction tx; try { tx = TransactionSerializer.Deserialize(request.SignedTransaction).transaction; } catch (InvalidTransactionException) { return(BadRequest(ErrorResponse.Create($"{nameof(request.SignedTransaction)} is invalid"))); } if (aggregate.IsBroadcasted) { return(Conflict()); } try { await _transactionBroadcaster.BroadcastTransaction(tx, aggregate); } catch (TransactionAlreadyBroadcastedException) { return(Conflict()); } aggregate.OnBroadcasted(DateTime.UtcNow); await _operationRepository.Save(aggregate); return(Ok()); }
public Task BroadcastAsync(BroadcastTransactionRequest request) { var entropy = _random.Next(0, 100); dynamic signed; try { signed = JsonConvert.DeserializeObject <dynamic>(request.SignedTransaction.DecodeToString()); } catch (JsonException ex) { throw new RequestValidationException("Failed to deserialize signed transaction", request.SignedTransaction, ex, nameof(request.SignedTransaction)); } var serializedContext = new Base64String((string)signed.Context).DecodeToString(); if (string.IsNullOrWhiteSpace(serializedContext)) { throw new RequestValidationException("Context is empty in the signed transaction"); } BuildTransferAmountTransactionRequest context; try { context = JsonConvert.DeserializeObject <BuildTransferAmountTransactionRequest>(serializedContext); } catch (JsonException ex) { throw new RequestValidationException("Failed to deserialize signed transaction context", serializedContext, ex, nameof(serializedContext)); } if (context.Expiration?.AfterMoment < DateTime.UtcNow) { throw new TransactionBroadcastingException(TransactionBroadcastingError.RebuildRequired, "Transaction is expired"); } if (entropy < 10) { throw new TransactionBroadcastingException(TransactionBroadcastingError.TransientFailure, "Nod is not available"); } return(Task.CompletedTask); }
public async Task Broadcast_transaction() { //ARRANGE string signedTransaction = "signedTransaction"; var client = PrepareClient <AppSettings>((options) => { var aggregator = CreateMocksAndSetupFactories(options); options.IntegrationName = $"{nameof(TransactionExecutorClientTests)}+{nameof(Broadcast_transaction)}"; aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease); aggregator.TransactionBroadcaster.Setup(x => x.BroadcastAsync(It.IsAny <BroadcastTransactionRequest>())) .Returns(Task.CompletedTask); }); //ACT && ASSERT var request = new BroadcastTransactionRequest(Base64String.Encode(signedTransaction)); await client.BroadcastTransactionAsync(request); //Assume everything is ok if no exceptions here }
public async Task <IActionResult> BroadcastTransaction([FromBody] BroadcastTransactionRequest request) { if (request == null) { throw new BusinessException("Unable deserialize request", ErrorCode.BadInputParameter); } try { await _broadcastService.BroadCastTransaction(request.OperationId, request.SignedTransaction); } catch (BusinessException e) when(e.Code == ErrorCode.TransactionAlreadyBroadcasted) { return(new StatusCodeResult(409)); } catch (BusinessException e) when(e.Code == ErrorCode.OperationNotFound) { return(new StatusCodeResult((int)HttpStatusCode.NoContent)); } return(Ok()); }
public void Internal_server_error_broadcast_transaction() { //ARRANGE string signedTransaction = "signedTransaction"; var client = PrepareClient <AppSettings>(options => { var aggregator = CreateMocksAndSetupFactories(options); options.IntegrationName = $"{nameof(TransactionExecutorClientTests)}+{nameof(Internal_server_error_broadcast_transaction)}"; aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease); aggregator.TransactionBroadcaster.Setup(x => x.BroadcastAsync(It.IsAny <BroadcastTransactionRequest>())) .ThrowsAsync(new Exception("Error")); }); //ACT && ASSERT Assert.ThrowsAsync <InternalServerErrorWebApiException>(async() => { var request = new BroadcastTransactionRequest(Base64String.Encode(signedTransaction)); await client.BroadcastTransactionAsync(request); }); }
public async Task <IActionResult> Broadcast([Required, FromBody] BroadcastTransactionRequest request) { if (request == null || request.OperationId.Equals(Guid.Empty)) { return(BadRequest(ErrorResponse.Create("Invalid parameter").AddModelError(nameof(request.OperationId), "Must be valid guid"))); } var broadcast = await _transactionService.GetTxBroadcastAsync(request.OperationId); if (!_transactionService.CheckSignature(request.SignedTransaction)) { var errorResponse = StellarErrorResponse.Create("Wrong signature", BlockchainErrorCode.BuildingShouldBeRepeated); return(BadRequest(errorResponse)); } if (broadcast != null) { return(new StatusCodeResult(StatusCodes.Status409Conflict)); } try { await _transactionService.BroadcastTxAsync(request.OperationId, request.SignedTransaction); } catch (BusinessException ex) { // technical / unknown problem if (string.IsNullOrWhiteSpace(ex.ErrorCode)) { throw; } var errorResponse = StellarErrorResponse.Create(ex.Message, (BlockchainErrorCode)Enum.Parse(typeof(BlockchainErrorCode), ex.ErrorCode)); return(BadRequest(errorResponse)); } return(Ok()); }
public async Task Broadcast([FromBody] BroadcastTransactionRequest model) { var signRequest = await _transactionSignRequestRepository.GetSignRequest(model.TransactionId); if (signRequest == null) { throw new BackendException("Transaction is not found", ErrorCode.BadTransaction); } if (signRequest.Invalidated == true) { throw new BackendException("Transaction was invalidated", ErrorCode.BadTransaction); } var initialTransaction = await _transactionBlobStorage.GetTransaction(model.TransactionId, TransactionBlobType.Initial); if (!TransactionComparer.CompareTransactions(initialTransaction, model.Transaction)) { throw new BackendException("Signed transaction is not equals to initial transaction", ErrorCode.BadTransaction); } var transaction = new Transaction(model.Transaction); if (transaction.Inputs.All(o => o.ScriptSig == null || o.ScriptSig.Length == 0)) { throw new BackendException("Transaction is not signed by client", ErrorCode.BadTransaction); } var fullSignedHex = signRequest.DoNotSign ? model.Transaction : await _signatureApiProvider.SignTransaction(model.Transaction); await _transactionBlobStorage.AddOrReplaceTransaction(model.TransactionId, TransactionBlobType.Signed, fullSignedHex); var fullSigned = new Transaction(fullSignedHex); await _broadcastService.BroadcastTransaction(model.TransactionId, fullSigned, useHandlers : false, savePaidFees : !signRequest.DoNotSign); }
public IResponse PostTransactionsBroadcast(BroadcastTransactionRequest model) { return(Request.Post("/transactions/broadcast").AddJsonBody(model).Build().Execute()); }
/// <summary> /// Broadcast fully signed bitcoin transaction to network /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> public static ApiException ApiTransactionBroadcastPost(this IBitcoinApi operations, BroadcastTransactionRequest model = default(BroadcastTransactionRequest)) { return(operations.ApiTransactionBroadcastPostAsync(model).GetAwaiter().GetResult()); }
/// <summary> /// Broadcast fully signed bitcoin transaction to network /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> /// <param name='cancellationToken'> /// The cancellation token. /// </param> public static async System.Threading.Tasks.Task <ApiException> ApiTransactionBroadcastPostAsync(this IBitcoinApi operations, BroadcastTransactionRequest model = default(BroadcastTransactionRequest), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { using (var _result = await operations.ApiTransactionBroadcastPostWithHttpMessagesAsync(model, null, cancellationToken).ConfigureAwait(false)) { return(_result.Body); } }
/// <summary> /// Broadcast fully signed bitcoin transaction to network /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='model'> /// </param> public static ApiException ApiTransactionBroadcastPost(this IBitcoinApi operations, BroadcastTransactionRequest model = default(BroadcastTransactionRequest)) { return(System.Threading.Tasks.Task.Factory.StartNew(s => ((IBitcoinApi)s).ApiTransactionBroadcastPostAsync(model), operations, System.Threading.CancellationToken.None, System.Threading.Tasks.TaskCreationOptions.None, System.Threading.Tasks.TaskScheduler.Default).Unwrap().GetAwaiter().GetResult()); }
public override async Task <BroadcastTransactionResponse> BroadcastTransaction(BroadcastTransactionRequest request, ServerCallContext context) { var operation = Guid.Parse(request.OperationId); var res = await _transferService.SendTransactionAsync(operation, request.BlockchainId, request.SignedTransaction); var response = new BroadcastTransactionResponse() { TransactionBroadcastResult = res switch { TransactionBroadcastResult.AlreadyBroadcasted => BroadcastTransactionResponse.Types.TransactionBroadcastResult.AlreadyBroadcasted, TransactionBroadcastResult.AmountIsTooSmall => BroadcastTransactionResponse.Types.TransactionBroadcastResult.AmountIsTooSmall, TransactionBroadcastResult.BuildingShouldBeRepeated => BroadcastTransactionResponse.Types.TransactionBroadcastResult.BuildingShouldBeRepeated, TransactionBroadcastResult.NotEnoughBalance => BroadcastTransactionResponse.Types.TransactionBroadcastResult.NotEnoughBalance, TransactionBroadcastResult.Success => BroadcastTransactionResponse.Types.TransactionBroadcastResult.Success, } }; return(response); }