/// <summary> /// Sends a transaction that has already been built. /// Use the /api/Wallet/build-transaction call to create transactions. /// </summary> /// <param name="request">An object containing the necessary parameters used to a send transaction request.</param> /// <returns>A JSON object containing information about the sent transaction.</returns> public async Task <WalletSendTransactionModel> SendTransaction(string rawHex) { WalletSendTransactionModel sendTransactionResult = await restClient.SendTransaction(rawHex); Guard.Null(sendTransactionResult, nameof(sendTransactionResult), $"An Error Occured When Trying To Get The sent transaction for '{rawHex}'"); return(sendTransactionResult); }
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())); } }
/// <summary> /// Sends a transaction. /// </summary> /// <param name="request">The hex representing the transaction.</param> /// <returns></returns> public WalletSendTransactionModel SendTransaction(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 { var transaction = new NBitcoin.Transaction(request.Hex); WalletSendTransactionModel model = new WalletSendTransactionModel { TransactionId = transaction.GetHash(), Outputs = new List <TransactionOutputModel>() }; foreach (var output in transaction.Outputs) { var isUnspendable = output.ScriptPubKey.IsUnspendable; model.Outputs.Add(new TransactionOutputModel { Address = isUnspendable ? null : output.ScriptPubKey.GetDestinationAddress(this.network).ToString(), Amount = output.Value, OpReturnData = isUnspendable ? Encoding.UTF8.GetString(output.ScriptPubKey.ToOps().Last().PushData) : null }); } this.walletManager.ProcessTransaction(transaction, null, null, false); this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); return(model); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); //return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); throw; } }
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.ConnectedNodes.Any()) { throw new WalletException("Can't send transaction: sending transaction requires at least one connection!"); } try { var transaction = new Transaction(request.Hex); WalletSendTransactionModel model = new WalletSendTransactionModel { TransactionId = transaction.GetHash(), Outputs = new List <TransactionOutputModel>() }; foreach (var output in transaction.Outputs) { model.Outputs.Add(new TransactionOutputModel { Address = output.ScriptPubKey.GetDestinationAddress(this.network).ToString(), Amount = output.Value, }); } this.walletManager.ProcessTransaction(transaction, null, null, false); this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); 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 async Task <IActionResult> SendTransactionAsync([FromBody] SendTransactionRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { return(BuildErrorResponse(this.ModelState)); } try { var transaction = new Transaction(request.Hex); WalletSendTransactionModel model = new WalletSendTransactionModel { TransactionId = transaction.GetHash(), Outputs = new List <TransactionOutputModel>() }; foreach (var output in transaction.Outputs) { model.Outputs.Add(new TransactionOutputModel { Address = output.ScriptPubKey.GetDestinationAddress(this.network).ToString(), Amount = output.Value, }); } bool broadcasted = await this.broadcasterManager.TryBroadcastAsync(transaction).ConfigureAwait(false); if (broadcasted) { return(this.Json(model)); } else { throw new Exception(string.Format("Transaction was not sent correctly. Investigate current instance of {0} for more information.", typeof(IBroadcasterManager).Name)); } } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public void DoTest() { var transactionRequest = new BuildTransactionRequest() { FeeAmount = "0.01", // Change this to the address that should receive the funds. OpReturnData = "PLv2NAsyn22cNbk5veopWCkypaN6DBR27L", AccountName = "account 0", AllowUnconfirmed = true, Recipients = new List <RecipientModel> { new RecipientModel { DestinationAddress = "2MyKFLbvhSouDYeAHhxsj9a5A4oV71j7SPR", Amount = "1.1" } }, Password = "******", WalletName = "test" }; WalletBuildTransactionModel model = Post <BuildTransactionRequest, WalletBuildTransactionModel>( "http://127.0.0.1:38221/api/wallet/build-transaction", transactionRequest); var transaction = new PosTransaction(model.Hex); var reader = new OpReturnDataReader(this.loggerFactory, Networks.Stratis.Testnet()); var extractor = new DepositExtractor(this.loggerFactory, this.federationGatewaySettings, reader, this.fullNode); IDeposit deposit = extractor.ExtractDepositFromTransaction(transaction, 2, 1); Assert.NotNull(deposit); Assert.Equal(transaction.GetHash(), deposit.Id); Assert.Equal(transactionRequest.OpReturnData, deposit.TargetAddress); Assert.Equal(Money.Parse(transactionRequest.Recipients[0].Amount), deposit.Amount); Assert.Equal((uint256)1, deposit.BlockHash); Assert.Equal(2, deposit.BlockNumber); // Post the transaction var sendRequest = new SendTransactionRequest() { Hex = model.Hex }; WalletSendTransactionModel model2 = Post <SendTransactionRequest, WalletSendTransactionModel>( "http://127.0.0.1:38221/api/wallet/send-transaction", sendRequest); }
/// <summary> /// Sends a transaction that has already been built. /// Use the /api/Wallet/build-transaction call to create transactions. /// </summary> /// <param name="request">An object containing the necessary parameters used to a send transaction request.</param> /// <returns>A JSON object containing information about the sent transaction.</returns> public async Task <WalletSendTransactionModel> SendTransaction(string rawHex) { try { Guard.Null(rawHex, nameof(rawHex), "Unable to send transaction, Provided rawHex Is NULL/Empty!"); SendTransactionRequest decodeTxRequest = new SendTransactionRequest { Hex = rawHex }; WalletSendTransactionModel response = await base.SendPostJSON <WalletSendTransactionModel>("/api/Wallet/send-transaction", decodeTxRequest); Guard.Null(response, nameof(response), "'api/Wallet/send-transaction' API Response Was Null!"); return(response); } catch (Exception ex) { logger.LogCritical($"An Error '{ex.Message}' Occured When Getting raw transaction For '{rawHex}'!", ex); throw; } }
public IActionResult SendWantedSystemMessageAsync([FromBody] SendWantedSystemMessageRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { return(ModelStateErrors.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); WalletSendTransactionModel model = new WalletSendTransactionModel { TransactionId = transaction.GetHash(), Outputs = new List <TransactionOutputModel>() }; foreach (var output in transaction.Outputs) { if (WantedSystemMessageTemplate.Instance.CheckScriptPubKey(output.ScriptPubKey)) { model.Outputs.Add(new TransactionOutputModel { Address = $"N/A (Wanted System Message)", Amount = output.Value }); } else { model.Outputs.Add(new TransactionOutputModel { Address = output.ScriptPubKey.GetDestinationAddress(this.network).ToString(), Amount = output.Value }); } } if (transaction.Inputs.All(tri => String.IsNullOrEmpty(tri.ScriptSig.ToString()))) { throw new Exception("This transcation is not signed. In order to publish a transaction on the network, it must be fully signed first."); } if (transaction.Inputs.Any(tri => String.IsNullOrEmpty(tri.ScriptSig.ToString()))) { throw new Exception("This transcation is only partially signed. In order to publish a transaction on the network, it must be fully signed first."); } this.walletManager.ProcessTransaction(transaction, null, null, false); this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
private async Task BuildAndSendDistributionTransactionsAsync() { foreach (SwapTransaction swapTransaction in this.swapTransactions) { if (this.distributedSwapTransactions.Any(d => d.TransactionHash == swapTransaction.TransactionHash)) { Console.WriteLine($"Swap already distributed: {swapTransaction.StraxAddress}:{Money.Satoshis(swapTransaction.SenderAmount).ToUnit(MoneyUnit.BTC)}"); continue; } try { var distributedSwapTransaction = new DistributedSwapTransaction(swapTransaction); var result = await $"http://localhost:{this.StraxNetwork.DefaultAPIPort}/api" .AppendPathSegment("wallet/build-transaction") .PostJsonAsync(new BuildTransactionRequest { WalletName = walletName, AccountName = "account 0", FeeType = "medium", Password = walletPassword, Recipients = this.GetRecipients(distributedSwapTransaction.StraxAddress, distributedSwapTransaction.SenderAmount) }) .ReceiveBytes(); WalletBuildTransactionModel buildTransactionModel = null; try { buildTransactionModel = JsonConvert.DeserializeObject <WalletBuildTransactionModel>(Encoding.ASCII.GetString(result)); } catch (Exception) { Console.WriteLine($"An error occurred processing swap {distributedSwapTransaction.TransactionHash}"); break; } distributedSwapTransaction.TransactionBuilt = true; WalletSendTransactionModel sendActionResult = await $"http://localhost:{this.StraxNetwork.DefaultAPIPort}/api" .AppendPathSegment("wallet/send-transaction") .PostJsonAsync(new SendTransactionRequest { Hex = buildTransactionModel.Hex }) .ReceiveJson <WalletSendTransactionModel>(); distributedSwapTransaction.TransactionSent = true; distributedSwapTransaction.TransactionSentHash = sendActionResult.TransactionId.ToString(); Console.WriteLine($"Swap transaction built and sent to {distributedSwapTransaction.StraxAddress}:{Money.Satoshis(distributedSwapTransaction.SenderAmount).ToUnit(MoneyUnit.BTC)}"); // Append to the file. using (FileStream stream = File.Open(Path.Combine(this.swapFilePath, distributedSwapTransactionsFile), FileMode.Append)) using (var writer = new StreamWriter(stream)) using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csv.WriteRecord(distributedSwapTransaction); csv.NextRecord(); } this.distributedSwapTransactions.Add(distributedSwapTransaction); await Task.Delay(TimeSpan.FromSeconds(1)); } catch (Exception ex) { Console.WriteLine(ex.Message); break; } finally { } } }
public void ConsensusManager_Fork_Occurs_When_Stake_Coins_Are_Spent_And_Found_In_Rewind_Data() { using (NodeBuilder builder = NodeBuilder.Create(this)) { var network = new StratisOverrideRegTest("stake_coins"); var sharedMnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve).ToString(); // MinerA requires an physical wallet to stake with. var minerA = builder.CreateStratisPosNode(network, "cm-10-minerA").OverrideDateTimeProvider().WithWallet(walletMnemonic: sharedMnemonic).Start(); var minerB = builder.CreateStratisPosNode(network, "cm-10-minerB").OverrideDateTimeProvider().WithWallet(walletMnemonic: sharedMnemonic).Start(); // MinerA mines 2 blocks to get the big premine coin and mature them (regtest maturity is 10). TestHelper.MineBlocks(minerA, 12); // Sync the peers A and B (height 3) TestHelper.ConnectAndSync(minerA, minerB); // Miner A will spend the coins WalletSendTransactionModel walletSendTransactionModel = $"http://localhost:{minerA.ApiPort}/api" .AppendPathSegment("wallet/splitcoins") .PostJsonAsync(new SplitCoinsRequest { WalletName = minerA.WalletName, AccountName = "account 0", WalletPassword = minerA.WalletPassword, TotalAmountToSplit = network.Consensus.PremineReward.ToString(), UtxosCount = 2 }) .ReceiveJson <WalletSendTransactionModel>().Result; TestBase.WaitLoop(() => minerA.FullNode.MempoolManager().InfoAll().Count > 0); TestHelper.MineBlocks(minerA, 12); TestBase.WaitLoop(() => minerA.FullNode.ConsensusManager().Tip.Height == 24); Assert.Empty(minerA.FullNode.MempoolManager().InfoAll()); TestBase.WaitLoop(() => TestHelper.AreNodesSynced(minerA, minerB)); // Disconnect Miner A and B. TestHelper.Disconnect(minerA, minerB); // Miner A stakes one coin. (height 13) var minterA = minerA.FullNode.NodeService <IPosMinting>(); minterA.Stake(new WalletSecret() { WalletName = "mywallet", WalletPassword = "******" }); TestBase.WaitLoop(() => minerA.FullNode.ConsensusManager().Tip.Height == 25); minterA.StopStake(); TestHelper.MineBlocks(minerB, 2); // this will push minerB total work to be highest var minterB = minerB.FullNode.NodeService <IPosMinting>(); minterB.Stake(new WalletSecret() { WalletName = WalletName, WalletPassword = Password }); TestBase.WaitLoop(() => minerB.FullNode.ConsensusManager().Tip.Height == 27); minterB.StopStake(); var expectedValidChainHeight = minerB.FullNode.ConsensusManager().Tip.Height; // Sync the network, minerA should switch to minerB. TestHelper.Connect(minerA, minerB); TestHelper.IsNodeSyncedAtHeight(minerA, expectedValidChainHeight); TestHelper.IsNodeSyncedAtHeight(minerB, expectedValidChainHeight); } }
public async Task <IActionResult> SendTransactionAsync([FromBody] SendTransactionRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { return(BuildErrorResponse(this.ModelState)); } try { var transaction = new Transaction(request.Hex); WalletSendTransactionModel model = new WalletSendTransactionModel { TransactionId = transaction.GetHash(), Outputs = new List <TransactionOutputModel>() }; foreach (var output in transaction.Outputs) { model.Outputs.Add(new TransactionOutputModel { Address = output.ScriptPubKey.GetDestinationAddress(this.network).ToString(), Amount = output.Value, }); } var result = await this.broadcasterManager.TryBroadcastAsync(transaction).ConfigureAwait(false); if (result == Bitcoin.Broadcasting.Success.Yes) { return(this.Json(model)); } if (result == Bitcoin.Broadcasting.Success.DontKnow) { // wait for propagation var waited = TimeSpan.Zero; var period = TimeSpan.FromSeconds(1); while (TimeSpan.FromSeconds(21) > waited) { // if broadcasts doesn't contain then success var transactionEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (transactionEntry != null && transactionEntry.State == Bitcoin.Broadcasting.State.Propagated) { return(this.Json(model)); } await Task.Delay(period).ConfigureAwait(false); waited += period; } } throw new TimeoutException("Transaction propagation has timed out. Lost connection?"); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }