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);
        }
예제 #2
0
        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());
        }
예제 #3
0
        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();
            }
        }
예제 #4
0
        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();
            }
        }
예제 #5
0
        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)
        }
예제 #6
0
        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);
        }
예제 #7
0
        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));
예제 #8
0
        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));
        }
예제 #9
0
        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();
            }
        }
예제 #10
0
        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()));
        }
예제 #11
0
        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);
        }
예제 #12
0
        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));
예제 #13
0
        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"));
        }
예제 #14
0
        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());
        }
예제 #15
0
        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));
        }
예제 #16
0
        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);
        }
예제 #17
0
        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();
        }
예제 #18
0
        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"));
        }
예제 #19
0
        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 { })
예제 #20
0
        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);
        }