private async Task <TransactionProcessor> CreateTransactionProcessorAsync([CallerMemberName] string callerName = "") { var datadir = EnvironmentHelpers.GetDataDir(Path.Combine("WalletWasabi", "Bench")); var dir = Path.Combine(datadir, callerName, "TransactionStore"); Console.WriteLine(dir); await IoHelpers.DeleteRecursivelyWithMagicDustAsync(dir); // Create the services. // 1. Create connection service. var nodes = new NodesGroup(Network.Main); var bitcoinStore = new BitcoinStore(); var serviceConfiguration = new ServiceConfiguration(2, 2, 21, 50, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 45678), Money.Coins(0.0001m)); // 2. Create wasabi synchronizer service. var synchronizer = new WasabiSynchronizer(Network.Main, bitcoinStore, () => new Uri("http://localhost:35474"), null); synchronizer.Start(requestInterval: TimeSpan.FromDays(1), TimeSpan.FromDays(1), 1000); // 3. Create key manager service. var keyManager = KeyManager.CreateNew(out _, "password"); // 4. Create chaumian coinjoin client. var chaumianClient = new CoinJoinClient(synchronizer, Network.Main, keyManager); // 5. Create wallet service. await bitcoinStore.InitializeAsync(dir, Network.Main); var workDir = Path.Combine(datadir, EnvironmentHelpers.GetMethodName()); var feeProviders = new FeeProviders(new[] { synchronizer }); var wallet = new WalletService(bitcoinStore, keyManager, synchronizer, nodes, workDir, serviceConfiguration, feeProviders); return(wallet.TransactionProcessor); }
public async Task IndexStoreTestsAsync() { var indexStore = new IndexStore(); var dir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName()); var network = Network.Main; await indexStore.InitializeAsync(dir, network, new HashChain()); }
public async Task TrustedNotifierNotifiesTxAsync() { var coreNode = await TestNodeBuilder.CreateAsync(); try { var rpc = coreNode.RpcClient; await rpc.GenerateAsync(101); var network = rpc.Network; var dir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName()); var addr = new Key().PubKey.GetSegwitAddress(network); var notifier = coreNode.TrustedNodeNotifyingBehavior; var txNum = 10; var txInvEventAwaiter = new EventsAwaiter <uint256>( h => notifier.TransactionInv += h, h => notifier.TransactionInv -= h, txNum); var txEventAwaiter = new EventsAwaiter <SmartTransaction>( h => notifier.Transaction += h, h => notifier.Transaction -= h, txNum); var txTasks = new List <Task <uint256> >(); var batch = rpc.PrepareBatch(); for (int i = 0; i < txNum; i++) { txTasks.Add(batch.SendToAddressAsync(addr, Money.Coins(1))); } var batchTask = batch.SendBatchAsync(); var aht = txInvEventAwaiter.WaitAsync(TimeSpan.FromSeconds(21)); var arrivedTxs = await txEventAwaiter.WaitAsync(TimeSpan.FromSeconds(21)); var arrivedHashes = await aht; await batchTask; var hashes = await Task.WhenAll(txTasks); foreach (var hash in arrivedHashes) { Assert.Contains(hash, hashes); } foreach (var hash in arrivedTxs.Select(x => x.GetHash())) { Assert.Contains(hash, hashes); } } finally { await coreNode.TryStopAsync(); } }
public async Task MempoolNotifiesAsync() { using var services = new HostedServices(); var coreNode = await TestNodeBuilder.CreateAsync(services); await services.StartAllAsync(CancellationToken.None); using var node = await coreNode.CreateNewP2pNodeAsync(); try { var network = coreNode.Network; var rpc = coreNode.RpcClient; var bitcoinStore = new BitcoinStore(); var dir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName()); await bitcoinStore.InitializeAsync(dir, network); await rpc.GenerateAsync(101); node.Behaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior()); node.VersionHandshake(); var addr = new Key().PubKey.GetSegwitAddress(network); var txNum = 10; var eventAwaiter = new EventsAwaiter <SmartTransaction>( h => bitcoinStore.MempoolService.TransactionReceived += h, h => bitcoinStore.MempoolService.TransactionReceived -= h, txNum); var txTasks = new List <Task <uint256> >(); var batch = rpc.PrepareBatch(); for (int i = 0; i < txNum; i++) { txTasks.Add(batch.SendToAddressAsync(addr, Money.Coins(1))); } var batchTask = batch.SendBatchAsync(); var stxs = await eventAwaiter.WaitAsync(TimeSpan.FromSeconds(21)); await batchTask; var hashes = await Task.WhenAll(txTasks); foreach (var stx in stxs) { Assert.Contains(stx.GetHash(), hashes); } } finally { await services.StopAllAsync(CancellationToken.None); node.Disconnect(); await coreNode.TryStopAsync(); } }
public RegTestFixture() { BackendNodeBuilder = NodeBuilder.CreateAsync(EnvironmentHelpers.GetMethodName()).GetAwaiter().GetResult(); BackendNodeBuilder.CreateNodeAsync().GetAwaiter().GetResult(); BackendNodeBuilder.StartAllAsync().GetAwaiter().GetResult(); BackendRegTestNode = BackendNodeBuilder.Nodes[0]; var connectionString = $"{BackendRegTestNode.Creds.UserName}:{BackendRegTestNode.Creds.Password}"; var testnetBackendDir = EnvironmentHelpers.GetDataDir(Path.Combine("WalletWasabi", "Tests", "Backend")); IoHelpers.DeleteRecursivelyWithMagicDustAsync(testnetBackendDir).GetAwaiter().GetResult(); Thread.Sleep(100); Directory.CreateDirectory(testnetBackendDir); Thread.Sleep(100); var config = new Config( BackendNodeBuilder.Network, connectionString, new IPEndPoint(IPAddress.Loopback, Network.Main.DefaultPort), new IPEndPoint(IPAddress.Loopback, Network.TestNet.DefaultPort), BackendRegTestNode.P2pEndPoint, new IPEndPoint(IPAddress.Loopback, Network.Main.RPCPort), new IPEndPoint(IPAddress.Loopback, Network.TestNet.RPCPort), BackendRegTestNode.RpcEndPoint); var configFilePath = Path.Combine(testnetBackendDir, "Config.json"); config.SetFilePath(configFilePath); config.ToFileAsync().GetAwaiter().GetResult(); var roundConfig = CreateRoundConfig(Money.Coins(0.1m), Constants.OneDayConfirmationTarget, 0.7, 0.1m, 100, 120, 60, 60, 60, 1, 24, true, 11); var roundConfigFilePath = Path.Combine(testnetBackendDir, "CcjRoundConfig.json"); roundConfig.SetFilePath(roundConfigFilePath); roundConfig.ToFileAsync().GetAwaiter().GetResult(); var conf = new ConfigurationBuilder() .AddInMemoryCollection(new[] { new KeyValuePair <string, string>("datadir", testnetBackendDir) }) .Build(); BackendEndPoint = $"http://localhost:{new Random().Next(37130, 38000)}/"; BackendHost = WebHost.CreateDefaultBuilder() .UseStartup <Startup>() .UseConfiguration(conf) .UseWebRoot("../../../../WalletWasabi.Backend/wwwroot") .UseUrls(BackendEndPoint) .Build(); Global = (Backend.Global)BackendHost.Services.GetService(typeof(Backend.Global)); var hostInitializationTask = BackendHost.RunWithTasksAsync(); Logger.LogInfo($"Started Backend webhost: {BackendEndPoint}"); var delayTask = Task.Delay(3000); Task.WaitAny(delayTask, hostInitializationTask); // Wait for server to initialize (Without this OSX CI will fail) }
public void CanSerialize() { string password = "******"; var filePath = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName(), "Wallet.json"); DeleteFileAndDirectoryIfExists(filePath); Logger.TurnOff(); Assert.Throws <FileNotFoundException>(() => KeyManager.FromFile(filePath)); Logger.TurnOn(); var manager = KeyManager.CreateNew(out _, password, filePath); KeyManager.FromFile(filePath); manager.ToFile(); manager.ToFile(); // assert it does not throw var random = new Random(); for (int i = 0; i < 1000; i++) { var isInternal = random.Next(2) == 0; var label = RandomString.Generate(21); var keyState = (KeyState)random.Next(3); manager.GenerateNewKey(label, keyState, isInternal, toFile: false); } manager.ToFile(); Assert.True(File.Exists(filePath)); var sameManager = KeyManager.FromFile(filePath); Assert.Equal(manager.ChainCode, sameManager.ChainCode); Assert.Equal(manager.EncryptedSecret, sameManager.EncryptedSecret); Assert.Equal(manager.ExtPubKey, sameManager.ExtPubKey); DeleteFileAndDirectoryIfExists(filePath); }
public async Task IoManagerTestsAsync() { var file1 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName(), $"file1.dat"); var file2 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName(), $"file2.dat"); Random random = new Random(); List <string> lines = new List <string>(); for (int i = 0; i < 1000; i++) { string line = new string(Enumerable.Repeat(Constants.Chars, 100) .Select(s => s[random.Next(s.Length)]).ToArray()); lines.Add(line); } // Single thread file operations. DigestableSafeMutexIoManager ioman1 = new DigestableSafeMutexIoManager(file1); // Delete the file if Exist. ioman1.DeleteMe(); Assert.False(ioman1.Exists()); Assert.False(File.Exists(ioman1.DigestFilePath)); // Write the data to the file. await ioman1.WriteAllLinesAsync(lines); Assert.True(ioman1.Exists()); // Check if the digest file is created. Assert.True(File.Exists(ioman1.DigestFilePath));
public async Task CreatesWalletDirectoriesAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); (string walletsPath, string walletsBackupPath) = await CleanupWalletDirectoriesAsync(baseDir); new WalletDirectories(baseDir); Assert.True(Directory.Exists(walletsPath)); Assert.True(Directory.Exists(walletsBackupPath)); // Testing what happens if the directories are already exist. new WalletDirectories(baseDir); Assert.True(Directory.Exists(walletsPath)); Assert.True(Directory.Exists(walletsBackupPath)); }
public async Task TestServicesAsync(string networkString) { await RuntimeParams.LoadAsync(); var network = Network.GetNetwork(networkString); var blocksToDownload = new HashSet <uint256>(); if (network == Network.Main) { blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0")); blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9")); blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629")); } else if (network == Network.TestNet) { blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524")); blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc")); blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66")); } else { throw new NotSupportedException($"{nameof(Network)} not supported: {network}."); } var addressManagerFolderPath = Path.Combine(Global.Instance.DataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var blocksFolderPath = Path.Combine(Global.Instance.DataDir, "Blocks", network.ToString()); var connectionParameters = new NodeConnectionParameters(); AddressManager addressManager = null; try { addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath); Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`."); } catch (DirectoryNotFoundException) { addressManager = new AddressManager(); } catch (FileNotFoundException) { addressManager = new AddressManager(); } catch (OverflowException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } catch (FormatException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); var mempoolService = new MempoolService(); connectionParameters.TemplateBehaviors.Add(new MempoolBehavior(mempoolService)); var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements); BitcoinStore bitcoinStore = new BitcoinStore(); await bitcoinStore.InitializeAsync(Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName()), network); KeyManager keyManager = KeyManager.CreateNew(out _, "password"); WasabiSynchronizer syncer = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint); WalletService walletService = new WalletService( bitcoinStore, keyManager, syncer, new CcjClient(syncer, network, keyManager, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint), mempoolService, nodes, Global.Instance.DataDir, new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(0.0001m))); Assert.True(Directory.Exists(blocksFolderPath)); try { mempoolService.TransactionReceived += MempoolService_TransactionReceived; nodes.Connect(); var times = 0; while (nodes.ConnectedNodes.Count < 3) { if (times > 4200) // 7 minutes { throw new TimeoutException("Connection test timed out."); } await Task.Delay(100); times++; } times = 0; while (Interlocked.Read(ref _mempoolTransactionCount) < 3) { if (times > 3000) // 3 minutes { throw new TimeoutException($"{nameof(MempoolService)} test timed out."); } await Task.Delay(100); times++; } foreach (var hash in blocksToDownload) { using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3))) { var block = await walletService.FetchBlockAsync(hash, cts.Token); Assert.True(File.Exists(Path.Combine(blocksFolderPath, hash.ToString()))); Logger.LogInfo <P2pTests>($"Full block is downloaded: {hash}."); } } } finally { nodes.ConnectedNodes.Added -= ConnectedNodes_Added; nodes.ConnectedNodes.Removed -= ConnectedNodes_Removed; mempoolService.TransactionReceived -= MempoolService_TransactionReceived; // So next test will download the block. foreach (var hash in blocksToDownload) { await walletService?.DeleteBlockAsync(hash); } if (walletService != null) { await walletService.StopAsync(); } if (Directory.Exists(blocksFolderPath)) { Directory.Delete(blocksFolderPath, recursive: true); } IoHelpers.EnsureContainingDirectoryExists(addressManagerFilePath); addressManager?.SavePeerFile(addressManagerFilePath, network); Logger.LogInfo <P2pTests>($"Saved {nameof(AddressManager)} to `{addressManagerFilePath}`."); nodes?.Dispose(); await syncer?.StopAsync(); } }
public async Task EnumerateFilesAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories(baseDir); var wallets = new List <string>(); var walletBackups = new List <string>(); const int NumberOfWallets = 4; for (int i = 0; i < NumberOfWallets; i++) { var walletFile = Path.Combine(walletDirectories.WalletsDir, $"FooWallet{i}.json"); var dummyFile = Path.Combine(walletDirectories.WalletsDir, $"FooWallet{i}.dummy"); var backupFile = Path.Combine(walletDirectories.WalletsBackupDir, $"FooWallet{i}.json"); await File.Create(walletFile).DisposeAsync(); await File.Create(dummyFile).DisposeAsync(); await File.Create(backupFile).DisposeAsync(); wallets.Add(walletFile); walletBackups.Add(backupFile); } Assert.True(wallets.ToHashSet().SetEquals(walletDirectories.EnumerateWalletFiles().Select(x => x.FullName).ToHashSet())); Assert.True(wallets.Concat(walletBackups).ToHashSet().SetEquals(walletDirectories.EnumerateWalletFiles(true).Select(x => x.FullName).ToHashSet())); }
public async Task EnsuresJsonAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories(baseDir); string walletName = "FooWallet"; string walletFileName = $"{walletName}.json"; (string walletPath, string walletBackupPath) = walletDirectories.GetWalletFilePaths(walletName); Assert.Equal(Path.Combine(walletDirectories.WalletsDir, walletFileName), walletPath); Assert.Equal(Path.Combine(walletDirectories.WalletsBackupDir, walletFileName), walletBackupPath); }
public async Task IoManagerTestsAsync() { var file1 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName(), $"file1.dat"); var file2 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName(), $"file2.dat"); Random random = new Random(); List <string> lines = new List <string>(); for (int i = 0; i < 1000; i++) { string line = RandomString.AlphaNumeric(100); lines.Add(line); } // Single thread file operations. DigestableSafeMutexIoManager ioman1 = new DigestableSafeMutexIoManager(file1); // Delete the file if Exist. ioman1.DeleteMe(); Assert.False(ioman1.Exists()); Assert.False(File.Exists(ioman1.DigestFilePath)); // Write the data to the file. await ioman1.WriteAllLinesAsync(lines); Assert.True(ioman1.Exists()); // Check if the digest file is created. Assert.True(File.Exists(ioman1.DigestFilePath));
public async Task GetNextWalletTestAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories(baseDir); Assert.Equal("Wallet0", walletDirectories.GetNextWalletName()); await File.Create(Path.Combine(walletDirectories.WalletsDir, $"Wallet0.json")).DisposeAsync(); await File.Create(Path.Combine(walletDirectories.WalletsDir, $"Wallet1.json")).DisposeAsync(); await File.Create(Path.Combine(walletDirectories.WalletsDir, $"Wallet3.json")).DisposeAsync(); // This should not matter. await File.Create(Path.Combine(walletDirectories.WalletsBackupDir, $"Wallet2.json")).DisposeAsync(); Assert.Equal("Wallet2", walletDirectories.GetNextWalletName()); Assert.Equal("Foo0", walletDirectories.GetNextWalletName("Foo")); }
public async Task EnumerateMissingDirAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); (string walletsPath, string walletsBackupPath) = await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories(baseDir); Assert.Empty(walletDirectories.EnumerateWalletFiles()); Directory.Delete(walletsBackupPath); Assert.Empty(walletDirectories.EnumerateWalletFiles()); Directory.Delete(walletsPath); Assert.Empty(walletDirectories.EnumerateWalletFiles()); Directory.Delete(baseDir); Assert.Empty(walletDirectories.EnumerateWalletFiles()); }
public async Task EnumerateOrdersByAccessAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories(baseDir); var walletFile1 = Path.Combine(walletDirectories.WalletsDir, $"FooWallet1.json"); await File.Create(walletFile1).DisposeAsync(); File.SetLastAccessTimeUtc(walletFile1, new DateTime(2005, 1, 1, 1, 1, 1, DateTimeKind.Utc)); var walletFile2 = Path.Combine(walletDirectories.WalletsDir, $"FooWallet2.json"); await File.Create(walletFile2).DisposeAsync(); File.SetLastAccessTimeUtc(walletFile2, new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc)); var walletFile3 = Path.Combine(walletDirectories.WalletsDir, $"FooWallet3.json"); await File.Create(walletFile3).DisposeAsync(); File.SetLastAccessTimeUtc(walletFile3, new DateTime(2010, 1, 1, 1, 1, 1, DateTimeKind.Utc)); var orderedWallets = new[] { walletFile3, walletFile1, walletFile2 }; Assert.Equal(orderedWallets, walletDirectories.EnumerateWalletFiles().Select(x => x.FullName)); }
public async Task IoTestsAsync() { var file = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName(), $"file.dat"); DigestableSafeMutexIoManager ioman = new DigestableSafeMutexIoManager(file); ioman.DeleteMe(); await ioman.WriteAllLinesAsync(new string[0], dismissNullOrEmptyContent : false); string RandomString() { StringBuilder builder = new StringBuilder(); var rnd = new Random(); char ch; for (int i = 0; i < rnd.Next(10, 100); i++) { ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * rnd.NextDouble() + 65))); builder.Append(ch); } return(builder.ToString()); }; var list = new List <string>(); async Task WriteNextLineAsync() { var next = RandomString(); lock (list) { list.Add(next); } using (await ioman.Mutex.LockAsync()) { var lines = (await ioman.ReadAllLinesAsync()).ToList(); lines.Add(next); await ioman.WriteAllLinesAsync(lines); } }; var t1 = new Thread(() => { for (var i = 0; i < 500; i++) { /* We have to block the Thread. * If we use async/await pattern then Join() function at the end will indicate that the Thread is finished - * which is not true bacause the WriteNextLineAsync() is not yet finished. The reason is that await will return execution * the to the calling thread it is detected as the thread is done. t1 and t2 and t3 will still run in parallel! */ WriteNextLineAsync().Wait(); } }); var t2 = new Thread(() => { for (var i = 0; i < 500; i++) { WriteNextLineAsync().Wait(); } }); var t3 = new Thread(() => { for (var i = 0; i < 500; i++) { WriteNextLineAsync().Wait(); } }); t1.Start(); t2.Start(); t3.Start(); await Task.Delay(100); t1.Join(); t2.Join(); t3.Join(); Assert.False(t1.IsAlive); Assert.False(t2.IsAlive); Assert.False(t3.IsAlive); var allLines = File.ReadAllLines(file); Assert.NotEmpty(allLines); /* Lines were added to the list and to the file parallel so the two data should be equal. * If we "substract" them from each other we should get empty array. */ var diff = allLines.Except(list); Assert.Empty(diff); }
public async Task IoManagerTestsAsync() { var file1 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName(), $"file1.dat"); var file2 = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName(), $"file2.dat"); Random random = new Random(); List <string> lines = new List <string>(); for (int i = 0; i < 1000; i++) { string line = new string(Enumerable.Repeat(Constants.Chars, 100) .Select(s => s[random.Next(s.Length)]).ToArray()); lines.Add(line); } // Single thread file operations. DigestableSafeMutexIoManager ioman1 = new DigestableSafeMutexIoManager(file1); // Delete the file if Exist. ioman1.DeleteMe(); Assert.False(ioman1.Exists()); Assert.False(File.Exists(ioman1.DigestFilePath)); // Write the data to the file. await ioman1.WriteAllLinesAsync(lines); Assert.True(ioman1.Exists()); // Check if the digest file is created. Assert.True(File.Exists(ioman1.DigestFilePath)); // Read back the content and check. bool IsStringArraysEqual(string[] lines1, string[] lines2) { if (lines1.Length != lines2.Length) { return(false); } for (int i = 0; i < lines1.Length; i++) { string line = lines2[i]; var readLine = lines1[i]; if (!line.Equals(readLine)) { return(false); } } return(true); } var readLines = await ioman1.ReadAllLinesAsync(); Assert.True(IsStringArraysEqual(readLines, lines.ToArray())); // Check digest file, and write only differ logic. // Write the same content, file should not be written. var currentDate = File.GetLastWriteTimeUtc(ioman1.FilePath); await Task.Delay(500); await ioman1.WriteAllLinesAsync(lines); var noChangeDate = File.GetLastWriteTimeUtc(ioman1.FilePath); Assert.Equal(currentDate, noChangeDate); // Write different content, file should be written. currentDate = File.GetLastWriteTimeUtc(ioman1.FilePath); await Task.Delay(500); lines.Add("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); await ioman1.WriteAllLinesAsync(lines); var newContentDate = File.GetLastWriteTimeUtc(ioman1.FilePath); Assert.NotEqual(currentDate, newContentDate); /* The next test is commented out because on mac and on linux File.Open does not lock the file * it can be still written by the ioman1.WriteAllLinesAsync(). Tried with FileShare.None FileShare.Delete * FileStream.Lock none of them are working or caused not supported on this platform exception. * So there is no OP system way to garantee that the file won't be written during another write operation. * For example git is using lock files to solve this problem. We are using system wide mutexes. * For now there is no other way to do this. Some useful links : * https://stackoverflow.com/questions/2751734/how-do-filesystems-handle-concurrent-read-write * https://github.com/dotnet/corefx/issues/5964 */ //using (File.OpenWrite(ioman1.FilePath)) //{ // // Should be OK because the same data is written. // await ioman1.WriteAllLinesAsync(lines); //} //using (File.OpenWrite(ioman1.FilePath)) //{ // // Should fail because different data is written. // await Assert.ThrowsAsync<IOException>(async () => await ioman1.WriteAllLinesAsync(lines)); //} await ioman1.WriteAllLinesAsync(lines); // Mutex tests. // Acquire the Mutex with a background thread. var myTask = Task.Run(async() => { using (await ioman1.Mutex.LockAsync()) { await Task.Delay(3000); } }); // Wait for the Task.Run to Acquire the Mutex. await Task.Delay(100); // Try to get the Mutex and save the time. DateTime timeOfstart = DateTime.Now; DateTime timeOfAcquired = default; using (await ioman1.Mutex.LockAsync()) { timeOfAcquired = DateTime.Now; } Assert.True(myTask.IsCompletedSuccessfully); var elapsed = timeOfAcquired - timeOfstart; Assert.InRange(elapsed, TimeSpan.FromMilliseconds(2000), TimeSpan.FromMilliseconds(4000)); // Simulate file write error and recovery logic. // We have only *.new and *.old files. File.Copy(ioman1.FilePath, ioman1.OldFilePath); File.Move(ioman1.FilePath, ioman1.NewFilePath); // At this point there is now OriginalFile. var newFile = await ioman1.ReadAllLinesAsync(); Assert.True(IsStringArraysEqual(newFile, lines.ToArray())); // Add one more line to have different data. lines.Add("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); await ioman1.WriteAllLinesAsync(lines); // Check recovery mechanism. Assert.True( File.Exists(ioman1.FilePath) && !File.Exists(ioman1.OldFilePath) && !File.Exists(ioman1.NewFilePath)); ioman1.DeleteMe(); Assert.False(ioman1.Exists()); // Check if directory is empty. var fileCount = Directory.EnumerateFiles(Path.GetDirectoryName(ioman1.FilePath)).Count(); Assert.Equal(0, fileCount); // Check Mutex usage on simultaneous file writes. DigestableSafeMutexIoManager ioman2 = new DigestableSafeMutexIoManager(file2); await Task.Run(async() => { using (await ioman1.Mutex.LockAsync()) { // Should not be a problem because they using different Mutexes. using (await ioman2.Mutex.LockAsync()) { await ioman1.WriteAllLinesAsync(lines); await ioman2.WriteAllLinesAsync(lines); ioman1.DeleteMe(); ioman2.DeleteMe(); } } }); // TryReplace test. var dummyFilePath = $"{ioman1.FilePath}dummy"; var dummyContent = new string[] { "banana", "peach" }; await File.WriteAllLinesAsync(dummyFilePath, dummyContent); await ioman1.WriteAllLinesAsync(lines); ioman1.TryReplaceMeWith(dummyFilePath); var fruits = await ioman1.ReadAllLinesAsync(); Assert.True(IsStringArraysEqual(dummyContent, fruits)); Assert.False(File.Exists(dummyFilePath)); ioman1.DeleteMe(); }
public async Task GetNextWalletTestAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories(baseDir); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 3.json")); Assert.Equal("Random Wallet", walletDirectories.GetNextWalletName()); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet.json")); Assert.Equal("Random Wallet 2", walletDirectories.GetNextWalletName()); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 2.json")); Assert.Equal("Random Wallet 4", walletDirectories.GetNextWalletName()); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 4.dat")); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 4")); Assert.Equal("Random Wallet 4", walletDirectories.GetNextWalletName()); File.Delete(Path.Combine(walletDirectories.WalletsDir, "Random Wallet.json")); File.Delete(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 3.json")); Assert.Equal("Random Wallet", walletDirectories.GetNextWalletName()); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet.json")); Assert.Equal("Random Wallet 3", walletDirectories.GetNextWalletName()); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 3.json")); File.Delete(Path.Combine(walletDirectories.WalletsDir, "Random Wallet 3.json")); Assert.Equal("Foo", walletDirectories.GetNextWalletName("Foo")); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Foo.json")); Assert.Equal("Foo 2", walletDirectories.GetNextWalletName("Foo")); IoHelpers.CreateOrOverwriteFile(Path.Combine(walletDirectories.WalletsDir, "Foo 2.json")); }
public async Task TestServicesAsync(string networkString) { await RuntimeParams.LoadAsync(); var network = Network.GetNetwork(networkString); var blocksToDownload = new List <uint256>(); if (network == Network.Main) { blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0")); blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9")); blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629")); } else if (network == Network.TestNet) { blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524")); blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc")); blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66")); } else { throw new NotSupportedNetworkException(network); } var dataDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName()); BitcoinStore bitcoinStore = new BitcoinStore(); await bitcoinStore.InitializeAsync(Path.Combine(dataDir, EnvironmentHelpers.GetMethodName()), network); var addressManagerFolderPath = Path.Combine(dataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var blocksFolderPath = Path.Combine(dataDir, "Blocks", network.ToString()); var connectionParameters = new NodeConnectionParameters(); AddressManager addressManager = null; try { addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath); Logger.LogInfo($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`."); } catch (DirectoryNotFoundException) { addressManager = new AddressManager(); } catch (FileNotFoundException) { addressManager = new AddressManager(); } catch (OverflowException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } catch (FormatException) { File.Delete(addressManagerFilePath); addressManager = new AddressManager(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); connectionParameters.TemplateBehaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior()); using var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements); KeyManager keyManager = KeyManager.CreateNew(out _, "password"); WasabiSynchronizer syncer = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint); ServiceConfiguration serviceConfig = new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)); CachedBlockProvider blockProvider = new CachedBlockProvider( new P2pBlockProvider(nodes, null, syncer, serviceConfig, network), new FileSystemBlockRepository(blocksFolderPath, network)); using Wallet wallet = Wallet.CreateAndRegisterServices( network, bitcoinStore, keyManager, syncer, nodes, dataDir, new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)), syncer, blockProvider); Assert.True(Directory.Exists(blocksFolderPath)); try { var mempoolTransactionAwaiter = new EventsAwaiter <SmartTransaction>( h => bitcoinStore.MempoolService.TransactionReceived += h, h => bitcoinStore.MempoolService.TransactionReceived -= h, 3); var nodeConnectionAwaiter = new EventsAwaiter <NodeEventArgs>( h => nodes.ConnectedNodes.Added += h, h => nodes.ConnectedNodes.Added -= h, 3); nodes.Connect(); var downloadTasks = new List <Task <Block> >(); using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(4)); foreach (var hash in blocksToDownload) { downloadTasks.Add(blockProvider.GetBlockAsync(hash, cts.Token)); } await nodeConnectionAwaiter.WaitAsync(TimeSpan.FromMinutes(3)); var i = 0; var hashArray = blocksToDownload.ToArray(); foreach (var block in await Task.WhenAll(downloadTasks)) { Assert.True(File.Exists(Path.Combine(blocksFolderPath, hashArray[i].ToString()))); i++; } await mempoolTransactionAwaiter.WaitAsync(TimeSpan.FromMinutes(1)); } finally { // So next test will download the block. foreach (var hash in blocksToDownload) { await blockProvider.BlockRepository.RemoveAsync(hash, CancellationToken.None); } if (wallet is { })
public async Task CorrestWalletDirectoryNameAsync() { var baseDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName(), EnvironmentHelpers.GetMethodName()); (string walletsPath, string walletsBackupPath) = await CleanupWalletDirectoriesAsync(baseDir); var walletDirectories = new WalletDirectories($" {baseDir} "); Assert.Equal(baseDir, walletDirectories.WorkDir); Assert.Equal(walletsPath, walletDirectories.WalletsDir); Assert.Equal(walletsBackupPath, walletDirectories.WalletsBackupDir); }