コード例 #1
0
        /// <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);
        }
コード例 #2
0
        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()));
            }
        }
コード例 #3
0
        /// <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;
            }
        }
コード例 #4
0
        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()));
            }
        }
コード例 #5
0
        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()));
            }
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        /// <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;
            }
        }
コード例 #8
0
        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()));
            }
        }
コード例 #9
0
        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
                {
                }
            }
        }
コード例 #10
0
        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);
            }
        }
コード例 #11
0
        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()));
            }
        }