public static async Task ReportFullHistoryAsync(WalletJob walletJob) { var history = await walletJob.GetSafeHistoryAsync(); if (!history.Any()) { Debug.WriteLine("Wallet has no history..."); return; } Debug.WriteLine(""); Debug.WriteLine("---------------------------------------------------------------------------"); Debug.WriteLine(@"Date Amount Confirmed Transaction Id"); Debug.WriteLine("---------------------------------------------------------------------------"); foreach (var record in history) { Debug.WriteLine($@"{record.TimeStamp.DateTime} {record.Amount} {record.Confirmed} {record.TransactionId}"); } Debug.WriteLine(""); }
public async Task SyncingTestAsync() { // load wallet Network network = Network.Main; string path = $"Wallets/Empty{network}.json"; const string password = ""; Safe safe = File.Exists(path) ? await Safe.LoadAsync(password, path) : (await Safe.CreateAsync(password, path, network)).Safe; Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}"); // create walletjob WalletJob walletJob = new WalletJob(); await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe); // note some event _fullyConnected = false; _syncedOnce = false; walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged += WalletJob_StateChanged; Assert.Empty(walletJob.SafeAccounts); Assert.Equal(0, walletJob.ConnectedNodeCount); Assert.Empty((await walletJob.GetTrackerAsync()).TrackedTransactions); Assert.Empty(await walletJob.GetSafeHistoryAsync()); Assert.Equal(WalletState.NotStarted, walletJob.State); Assert.True(walletJob.TracksDefaultSafe); // start syncing var cts = new CancellationTokenSource(); var walletJobTask = walletJob.StartAsync(cts.Token); Assert.NotEqual(WalletState.NotStarted, walletJob.State); Task reportTask = Helpers.ReportAsync(cts.Token, walletJob); try { // wait until fully synced and connected while (!_fullyConnected) { await Task.Delay(10); } while (!_syncedOnce) { await Task.Delay(1000); } Assert.Equal(WalletState.Synced, walletJob.State); Assert.NotEqual(Height.Unknown, await walletJob.GetCreationHeightAsync()); Assert.Empty((await walletJob.GetTrackerAsync()).TrackedTransactions); Assert.Empty(await walletJob.GetSafeHistoryAsync()); var headerHeightResult = await walletJob.TryGetHeaderHeightAsync(); Assert.True(headerHeightResult.Success); var expectedBlockCount = headerHeightResult.Height.Value - (await walletJob.GetCreationHeightAsync()).Value + 1; Assert.Equal(expectedBlockCount, (await walletJob.GetTrackerAsync()).BlockCount); Assert.NotEmpty((await walletJob.GetTrackerAsync()).TrackedScriptPubKeys); Assert.Empty((await walletJob.GetTrackerAsync()).TrackedTransactions); } finally { cts?.Cancel(); await Task.WhenAll(reportTask, walletJobTask); walletJob.ConnectedNodeCountChanged -= WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged -= WalletJob_StateChanged; cts?.Dispose(); reportTask?.Dispose(); walletJobTask?.Dispose(); } }
public async Task RealHistoryTestAsync() { // load wallet Network network = Network.TestNet; string path = Path.Combine(Helpers.CommittedWalletsFolderPath, $"HiddenWallet.json"); const string password = ""; // I change it because I am using a very old wallet to test Safe.EarliestPossibleCreationTime = DateTimeOffset.ParseExact("2016-12-18", "yyyy-MM-dd", CultureInfo.InvariantCulture); Safe safe = await Safe.LoadAsync(password, path); Assert.Equal(network, safe.Network); Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}"); // create walletjob var walletJob = new WalletJob { MaxCleanAddressCount = 79 }; await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe); // note some event walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged; _syncedOnce = false; walletJob.StateChanged += WalletJob_StateChanged; Assert.Empty(walletJob.SafeAccounts); Assert.Equal(0, walletJob.ConnectedNodeCount); Assert.Equal(WalletState.NotStarted, walletJob.State); Assert.True(walletJob.TracksDefaultSafe); // start syncing var cts = new CancellationTokenSource(); var walletJobTask = walletJob.StartAsync(cts.Token); Assert.NotEqual(WalletState.NotStarted, walletJob.State); Task reportTask = Helpers.ReportAsync(cts.Token, walletJob); try { // wait until fully synced while (!_syncedOnce) { await Task.Delay(1000); } Assert.Equal(WalletState.Synced, walletJob.State); Assert.NotEqual(Height.Unknown, await walletJob.GetCreationHeightAsync()); var headerHeightResult = await walletJob.TryGetHeaderHeightAsync(); Assert.True(headerHeightResult.Success); Assert.NotEmpty((await walletJob.GetTrackerAsync()).TrackedScriptPubKeys); await Helpers.ReportFullHistoryAsync(walletJob); // 0. Query all operations, grouped our used safe addresses int MinUnusedKeyNum = 74; Dictionary <BitcoinAddress, List <BalanceOperation> > operationsPerAddresses = await Helpers.QueryOperationsPerSafeAddressesAsync(new QBitNinjaClient(safe.Network), safe, MinUnusedKeyNum); Dictionary <uint256, List <BalanceOperation> > operationsPerTransactions = QBitNinjaJutsus.GetOperationsPerTransactions(operationsPerAddresses); // 3. Create history records from the transactions // History records is arbitrary data we want to show to the user var txHistoryRecords = new List <(DateTimeOffset FirstSeen, Money Amount, int Confirmations, uint256 TxId)>(); foreach (var elem in operationsPerTransactions) { var amount = Money.Zero; foreach (var op in elem.Value) { amount += op.Amount; } var firstOp = elem.Value.First(); txHistoryRecords .Add(( firstOp.FirstSeen, amount, firstOp.Confirmations, elem.Key)); } // 4. Order the records by confirmations and time (Simply time does not work, because of a QBitNinja issue) var qBitHistoryRecords = txHistoryRecords .OrderByDescending(x => x.Confirmations) // Confirmations .ThenBy(x => x.FirstSeen); // FirstSeen var fullSpvHistoryRecords = await walletJob.GetSafeHistoryAsync(); // This won't be equal QBit doesn't show us this transaction: 2017.01.04. 16:24:49 0.00000000 True 77b10ff78aab2e41764a05794c4c464922c73f0c23356190429833ce68fd7be9 // Assert.Equal(qBitHistoryRecords.Count(), fullSpvHistoryRecords.Count()); HashSet <WalletHistoryRecord> qBitFoundItToo = new HashSet <WalletHistoryRecord>(); // Assert all record found by qbit also found by spv and they are identical foreach (var record in qBitHistoryRecords) { WalletHistoryRecord found = fullSpvHistoryRecords.FirstOrDefault(x => x.TransactionId == record.TxId); Assert.NotEqual(default, found);
public async Task SendTestAsync() { Network network = Network.TestNet; SafeAccount account = new SafeAccount(1); string path = Path.Combine(Helpers.CommittedWalletsFolderPath, $"Sending{network}.json"); const string password = ""; Safe safe = await Safe.LoadAsync(password, path); Assert.Equal(network, safe.Network); Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}"); // create walletjob WalletJob walletJob = new WalletJob(); await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe, trackDefaultSafe : false, accountsToTrack : account); // note some event walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged += WalletJob_StateChanged; // start syncing var cts = new CancellationTokenSource(); var walletJobTask = walletJob.StartAsync(cts.Token); Task reportTask = Helpers.ReportAsync(cts.Token, walletJob); try { // wait until blocks are synced while (walletJob.State <= WalletState.SyncingMemPool) { await Task.Delay(1000); } foreach (var r in await walletJob.GetSafeHistoryAsync(account)) { Debug.WriteLine(r.TransactionId); } # region Basic var receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); var getBalanceResult = await walletJob.GetBalanceAsync(account); var bal = getBalanceResult.Available; Money amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; var res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Equal(amountToSend, res.ActiveOutput.Value); Assert.NotNull(res.ChangeOutput); Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); var foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); _txProbArrived = false; _prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count; _currentWalletJob = walletJob; (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync; var sendRes = await walletJob.SendTransactionAsync(res.Transaction); Assert.True(sendRes.Success); Assert.Empty(sendRes.FailingReason); while (!_txProbArrived) { Debug.WriteLine("Waiting for transaction..."); await Task.Delay(1000); } Debug.WriteLine("TrackedTransactions collection changed"); Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == res.Transaction.GetHash()); Debug.WriteLine("Transaction arrived"); receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); bal = (await walletJob.GetBalanceAsync(account)).Available; amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; #endregion #region SubtractFeeFromAmount receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); getBalanceResult = await walletJob.GetBalanceAsync(account); bal = getBalanceResult.Available; amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true, subtractFeeFromAmount : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Equal(amountToSend - res.Fee, res.ActiveOutput.Value); Assert.NotNull(res.ChangeOutput); Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend - res.Fee, output.Value); } } Assert.True(foundReceive); #endregion #region CustomChange receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); var customChange = new Key().ScriptPubKey; getBalanceResult = await walletJob.GetBalanceAsync(account); bal = getBalanceResult.Available; amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true, subtractFeeFromAmount : true, customChangeScriptPubKey : customChange); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Equal(amountToSend - res.Fee, res.ActiveOutput.Value); Assert.NotNull(res.ChangeOutput); Assert.Equal(customChange, res.ChangeOutput.ScriptPubKey); Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend - res.Fee, output.Value); } } Assert.True(foundReceive); #endregion #region LowFee res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Equal(amountToSend, res.ActiveOutput.Value); Assert.NotNull(res.ChangeOutput); Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion #region MediumFee res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Medium, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Equal(amountToSend, res.ActiveOutput.Value); Assert.NotNull(res.ChangeOutput); Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion #region HighFee res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.High, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Equal(amountToSend, res.ActiveOutput.Value); Assert.NotNull(res.ChangeOutput); Assert.Contains(res.Transaction.Outputs, x => x.Value == res.ChangeOutput.Value); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"Change Output: {res.ChangeOutput.Value.ToString(false, true)} {res.ChangeOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); Assert.InRange(res.Fee, Money.Zero, res.Fee); Assert.InRange(res.Fee, res.Fee, res.Fee); _txProbArrived = false; _prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count; _currentWalletJob = walletJob; (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync; sendRes = await walletJob.SendTransactionAsync(res.Transaction); Assert.True(sendRes.Success); Assert.Empty(sendRes.FailingReason); while (_txProbArrived == false) { Debug.WriteLine("Waiting for transaction..."); await Task.Delay(1000); } Debug.WriteLine("TrackedTransactions collection changed"); Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == res.Transaction.GetHash()); Debug.WriteLine("Transaction arrived"); #endregion #region MaxAmount receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); bal = (await walletJob.GetBalanceAsync(account)).Available; res = await walletJob.BuildTransactionAsync(receive, Money.Zero, FeeType.Low, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Null(res.ChangeOutput); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); Assert.Single(res.Transaction.Outputs); var maxBuiltTxOutput = res.Transaction.Outputs.Single(); Assert.Equal(receive, maxBuiltTxOutput.ScriptPubKey); Assert.Equal(bal.Confirmed + bal.Unconfirmed - res.Fee, maxBuiltTxOutput.Value); #endregion #region InputSelection receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); bal = (await walletJob.GetBalanceAsync(account)).Available; var inputCountBefore = res.SpentCoins.Count(); res = await walletJob.BuildTransactionAsync(receive, Money.Zero, FeeType.Low, account, allowUnconfirmed : true, allowedInputs : res.SpentCoins.Where((x, i) => i == 0 || i % 2 == 0).Select(x => x.Outpoint)); Assert.True(inputCountBefore >= res.SpentCoins.Count()); Assert.Equal(res.SpentCoins.Count(), res.Transaction.Inputs.Count); Assert.True(res.Success); Assert.Empty(res.FailingReason); Assert.Equal(receive, res.ActiveOutput.ScriptPubKey); Assert.Null(res.ChangeOutput); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Active Output: {res.ActiveOutput.Value.ToString(false, true)} {res.ActiveOutput.ScriptPubKey.GetDestinationAddress(network)}"); Debug.WriteLine($"TxId: {res.Transaction.GetHash()}"); Assert.Single(res.Transaction.Outputs); res = await walletJob.BuildTransactionAsync(receive, Money.Zero, FeeType.Low, account, allowUnconfirmed : true, allowedInputs : new[] { res.SpentCoins.Select(x => x.Outpoint).First() }); Assert.Single(res.Transaction.Inputs); Assert.Single(res.Transaction.Outputs); Assert.Single(res.SpentCoins); Assert.Null(res.ChangeOutput); #endregion }
private async Task UpdateHistoryRelatedMembersAsync() { // history var aliceHistory = (await _walletJob.GetSafeHistoryAsync(AliceAccount)).OrderByDescending(x => x.TimeStamp); var bobHistory = (await _walletJob.GetSafeHistoryAsync(BobAccount)).OrderByDescending(x => x.TimeStamp); var hra = new List <HistoryRecordModel>(); foreach (var rec in aliceHistory) { string height; if (rec.BlockHeight.Type == HeightType.Chain) { height = rec.BlockHeight.Value.ToString(); } else { height = ""; } hra.Add(new HistoryRecordModel { Amount = rec.Amount.ToString(true, true), Confirmed = rec.Confirmed, Height = height, TxId = rec.TransactionId.ToString() }); } _historyResponseAlice.History = hra.ToArray(); var hrb = new List <HistoryRecordModel>(); foreach (var rec in bobHistory) { string height; if (rec.BlockHeight.Type == HeightType.Chain) { height = rec.BlockHeight.Value.ToString(); } else { height = ""; } hrb.Add(new HistoryRecordModel { Amount = rec.Amount.ToString(true, true), Confirmed = rec.Confirmed, Height = height, TxId = rec.TransactionId.ToString() }); } _historyResponseBob.History = hrb.ToArray(); // balances var getBalanceResult = await _walletJob.GetBalanceAsync(AliceAccount); var aa = getBalanceResult.Available; var getBalanceResult2 = await _walletJob.GetBalanceAsync(BobAccount); var ab = getBalanceResult2.Available; _availableAlice = aa.Confirmed; _incomingAlice = aa.Unconfirmed; _availableBob = ab.Confirmed; _incomingBob = ab.Unconfirmed; // receive var ua = (await _walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, AliceAccount, HdPathType.Receive)).ToArray(); var ub = (await _walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, BobAccount, HdPathType.Receive)).ToArray(); _receiveResponseAlice.Addresses = new string[7]; _receiveResponseBob.Addresses = new string[7]; var network = _walletJob.Safe.Network; for (int i = 0; i < 7; i++) { if (ua[i] != null) { _receiveResponseAlice.Addresses[i] = ua[i].GetDestinationAddress(network).ToString(); } else { _receiveResponseAlice.Addresses[i] = ""; } if (ub[i] != null) { _receiveResponseBob.Addresses[i] = ub[i].GetDestinationAddress(network).ToString(); } else { _receiveResponseBob.Addresses[i] = ""; } } _receiveResponseAlice.TraditionalAddress = (await _walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2PublicKeyHash, AliceAccount, HdPathType.Receive)).FirstOrDefault().GetDestinationAddress(network).ToString(); _receiveResponseBob.TraditionalAddress = (await _walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2PublicKeyHash, BobAccount, HdPathType.Receive)).FirstOrDefault().GetDestinationAddress(network).ToString(); }
public async Task SendsFailGracefullyTestAsync() { Network network = Network.TestNet; SafeAccount account = new SafeAccount(1); string path = Path.Combine(Helpers.CommittedWalletsFolderPath, $"Sending{network}.json"); const string password = ""; Safe safe = await Safe.LoadAsync(password, path, network); Assert.Equal(network, safe.Network); Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}"); // create walletjob WalletJob walletJob = new WalletJob(); await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe, trackDefaultSafe : false, accountsToTrack : account); // note some event walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged += WalletJob_StateChanged; // start syncing var cts = new CancellationTokenSource(); var walletJobTask = walletJob.StartAsync(cts.Token); Task reportTask = Helpers.ReportAsync(cts.Token, walletJob); try { // wait until blocks are synced while (walletJob.State <= WalletState.SyncingMemPool) { await Task.Delay(1000); } var history = await walletJob.GetSafeHistoryAsync(account); foreach (var record in history) { Debug.WriteLine($"{record.TransactionId} {record.Amount} {record.Confirmed}"); } var receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); var bal = (await walletJob.GetBalanceAsync(account)).Available; // Not enough fee Money amountToSend = (bal.Confirmed + bal.Unconfirmed) - new Money(1m, MoneyUnit.Satoshi); var res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.False(res.Success); Assert.NotEmpty(res.FailingReason); Debug.WriteLine($"Expected FailingReason: {res.FailingReason}"); // That's not how you spend all amountToSend = (bal.Confirmed + bal.Unconfirmed); res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.False(res.Success); Assert.NotEmpty(res.FailingReason); Debug.WriteLine($"Expected FailingReason: {res.FailingReason}"); // Too much amountToSend = (bal.Confirmed + bal.Unconfirmed) + new Money(1, MoneyUnit.BTC); res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.True(res.Success == false); Assert.True(res.FailingReason != ""); Debug.WriteLine($"Expected FailingReason: {res.FailingReason}"); // Minus amountToSend = new Money(-1m, MoneyUnit.BTC); res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.False(res.Success); Assert.NotEmpty(res.FailingReason); Debug.WriteLine($"Expected FailingReason: {res.FailingReason}"); // Default account is disabled amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; await Assert.ThrowsAsync <NotSupportedException>(async() => await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, allowUnconfirmed: true)).ContinueWith(t => {}); // No such account amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; await Assert.ThrowsAsync <NotSupportedException>(async() => await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, new SafeAccount(23421), allowUnconfirmed: true)).ContinueWith(t => { }); } finally { cts?.Cancel(); await Task.WhenAll(reportTask, walletJobTask); walletJob.ConnectedNodeCountChanged -= WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged -= WalletJob_StateChanged; cts?.Dispose(); reportTask?.Dispose(); walletJobTask?.Dispose(); } }
public async Task SendTestAsync() { Network network = Network.TestNet; SafeAccount account = new SafeAccount(1); string path = Path.Combine(Helpers.CommittedWalletsFolderPath, $"Sending{network}.json"); const string password = ""; Safe safe = await Safe.LoadAsync(password, path); Assert.Equal(network, safe.Network); Debug.WriteLine($"Unique Safe ID: {safe.UniqueId}"); // create walletjob WalletJob walletJob = new WalletJob(); await walletJob.InitializeAsync(Helpers.SocksPortHandler, Helpers.ControlPortClient, safe, trackDefaultSafe : false, accountsToTrack : account); // note some event walletJob.ConnectedNodeCountChanged += WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged += WalletJob_StateChanged; // start syncing var cts = new CancellationTokenSource(); var walletJobTask = walletJob.StartAsync(cts.Token); Task reportTask = Helpers.ReportAsync(cts.Token, walletJob); try { // wait until blocks are synced while (walletJob.State <= WalletState.SyncingMemPool) { await Task.Delay(1000); } foreach (var r in await walletJob.GetSafeHistoryAsync(account)) { Debug.WriteLine(r.TransactionId); } var record = (await walletJob.GetSafeHistoryAsync(account)).FirstOrDefault(); Debug.WriteLine(record.Confirmed); Debug.WriteLine(record.Amount); var receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); var getBalanceResult = await walletJob.GetBalanceAsync(account); var bal = getBalanceResult.Available; Money amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; var res = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Transaction: {res.Transaction}"); var foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); _txProbArrived = false; _prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count; _currentWalletJob = walletJob; (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync; var sendRes = await walletJob.SendTransactionAsync(res.Transaction); Assert.True(sendRes.Success); Assert.Empty(sendRes.FailingReason); while (!_txProbArrived) { Debug.WriteLine("Waiting for transaction..."); await Task.Delay(1000); } Debug.WriteLine("TrackedTransactions collection changed"); Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == res.Transaction.GetHash()); Debug.WriteLine("Transaction arrived"); receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); bal = (await walletJob.GetBalanceAsync(account)).Available; amountToSend = (bal.Confirmed + bal.Unconfirmed) / 2; #region LowFee var resLow = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Low, account, allowUnconfirmed : true); Assert.True(resLow.Success); Assert.Empty(resLow.FailingReason); Debug.WriteLine($"Fee: {resLow.Fee}"); Debug.WriteLine($"FeePercentOfSent: {resLow.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {resLow.SpendsUnconfirmed}"); Debug.WriteLine($"Transaction: {resLow.Transaction}"); foundReceive = false; Assert.InRange(resLow.Transaction.Outputs.Count, 1, 2); foreach (var output in resLow.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion #region MediumFee var resMedium = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.Medium, account, allowUnconfirmed : true); Assert.True(resMedium.Success); Assert.Empty(resMedium.FailingReason); Debug.WriteLine($"Fee: {resMedium.Fee}"); Debug.WriteLine($"FeePercentOfSent: {resMedium.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {resMedium.SpendsUnconfirmed}"); Debug.WriteLine($"Transaction: {resMedium.Transaction}"); foundReceive = false; Assert.InRange(resMedium.Transaction.Outputs.Count, 1, 2); foreach (var output in resMedium.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion #region HighFee var resHigh = await walletJob.BuildTransactionAsync(receive, amountToSend, FeeType.High, account, allowUnconfirmed : true); Assert.True(resHigh.Success); Assert.Empty(resHigh.FailingReason); Debug.WriteLine($"Fee: {resHigh.Fee}"); Debug.WriteLine($"FeePercentOfSent: {resHigh.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {resHigh.SpendsUnconfirmed}"); Debug.WriteLine($"Transaction: {resHigh.Transaction}"); foundReceive = false; Assert.InRange(resHigh.Transaction.Outputs.Count, 1, 2); foreach (var output in resHigh.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(amountToSend, output.Value); } } Assert.True(foundReceive); #endregion Assert.InRange(resLow.Fee, Money.Zero, resMedium.Fee); Assert.InRange(resMedium.Fee, resLow.Fee, resHigh.Fee); _txProbArrived = false; _prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count; _currentWalletJob = walletJob; (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync; sendRes = await walletJob.SendTransactionAsync(resHigh.Transaction); Assert.True(sendRes.Success); Assert.Empty(sendRes.FailingReason); while (_txProbArrived == false) { Debug.WriteLine("Waiting for transaction..."); await Task.Delay(1000); } Debug.WriteLine("TrackedTransactions collection changed"); Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == resHigh.Transaction.GetHash()); Debug.WriteLine("Transaction arrived"); receive = (await walletJob.GetUnusedScriptPubKeysAsync(AddressType.Pay2WitnessPublicKeyHash, account, HdPathType.Receive)).FirstOrDefault(); bal = (await walletJob.GetBalanceAsync(account)).Available; res = await walletJob.BuildTransactionAsync(receive, Money.Zero, FeeType.Low, account, allowUnconfirmed : true); Assert.True(res.Success); Assert.Empty(res.FailingReason); Debug.WriteLine($"Fee: {res.Fee}"); Debug.WriteLine($"FeePercentOfSent: {res.FeePercentOfSent} %"); Debug.WriteLine($"SpendsUnconfirmed: {res.SpendsUnconfirmed}"); Debug.WriteLine($"Transaction: {res.Transaction}"); foundReceive = false; Assert.InRange(res.Transaction.Outputs.Count, 1, 2); foreach (var output in res.Transaction.Outputs) { if (output.ScriptPubKey == receive) { foundReceive = true; Assert.Equal(bal.Confirmed + bal.Unconfirmed - res.Fee, output.Value); } } Assert.True(foundReceive); _txProbArrived = false; _prevCount = (await walletJob.GetTrackerAsync()).TrackedTransactions.Count; _currentWalletJob = walletJob; (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged += TrackedTransactions_CollectionChangedAsync; sendRes = await walletJob.SendTransactionAsync(res.Transaction); Assert.True(sendRes.Success); Assert.Empty(sendRes.FailingReason); while (_txProbArrived == false) { Debug.WriteLine("Waiting for transaction..."); await Task.Delay(1000); } Debug.WriteLine("TrackedTransactions collection changed"); Assert.Contains((await walletJob.GetTrackerAsync()).TrackedTransactions, x => x.Transaction.GetHash() == res.Transaction.GetHash()); Debug.WriteLine("Transaction arrived"); } finally { (await walletJob.GetTrackerAsync()).TrackedTransactions.CollectionChanged -= TrackedTransactions_CollectionChangedAsync; cts.Cancel(); await Task.WhenAll(reportTask, walletJobTask); walletJob.ConnectedNodeCountChanged -= WalletJob_ConnectedNodeCountChanged; walletJob.StateChanged -= WalletJob_StateChanged; cts?.Dispose(); reportTask?.Dispose(); walletJobTask?.Dispose(); } }