예제 #1
0
        public async Task <CoreNode> CreateNodeAsync(bool start = false)
        {
            var child = Path.Combine(Root, Last.ToString());

            Last++;
            try
            {
                var cfgPath = Path.Combine(child, "data", "bitcoin.conf");
                if (File.Exists(cfgPath))
                {
                    var config      = NodeConfigParameters.Load(cfgPath);
                    var rpcPort     = config["regtest.rpcport"];
                    var rpcUser     = config["regtest.rpcuser"];
                    var rpcPassword = config["regtest.rpcpassword"];
                    var pidFileName = config["regtest.pid"];
                    var credentials = new NetworkCredential(rpcUser, rpcPassword);
                    try
                    {
                        var rpc = new RPCClient(credentials, new Uri("http://127.0.0.1:" + rpcPort + "/"), Network.RegTest);
                        await rpc.StopAsync();

                        var pidFile = Path.Combine(child, "data", "regtest", pidFileName);
                        if (File.Exists(pidFile))
                        {
                            var pid = File.ReadAllText(pidFile);
                            using var process = Process.GetProcessById(int.Parse(pid));
                            process.WaitForExit();
                        }
                        else
                        {
                            var allProcesses      = Process.GetProcesses();
                            var bitcoindProcesses = allProcesses.Where(x => x.ProcessName.Contains("bitcoind"));
                            if (bitcoindProcesses.Count() == 1)
                            {
                                var bitcoind = bitcoindProcesses.First();
                                bitcoind.WaitForExit();
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
                await IoHelpers.DeleteRecursivelyWithMagicDustAsync(child);
                await TryRemoveWorkingDirectoryAsync();

                Directory.CreateDirectory(WorkingDirectory);
            }
            catch (DirectoryNotFoundException)
            {
            }
            var node = await CoreNode.CreateAsync(child, this);

            Nodes.Add(node);
            if (start)
            {
                await node.StartAsync();
            }
            return(node);
        }
예제 #2
0
        public async Task TryKillAsync(bool cleanFolder = true)
        {
            try
            {
                using (await KillerLock.LockAsync())
                {
                    try
                    {
                        await CreateRpcClient().StopAsync();

                        if (!Process.WaitForExit(20000))
                        {
                            //log this
                        }
                    }
                    catch (Exception)
                    { }

                    State = CoreNodeState.Killed;
                }
                if (cleanFolder)
                {
                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(Folder);
                }
            }
            catch
            { }
        }
        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);
        }
예제 #4
0
 private async Task CleanFolderAsync()
 {
     try
     {
         await IoHelpers.DeleteRecursivelyWithMagicDustAsync(Folder);
     }
     catch (DirectoryNotFoundException) { }
 }
예제 #5
0
        public static async Task <CoreNode> CreateAsync(string folder, NodeBuilder builder)
        {
            await IoHelpers.DeleteRecursivelyWithMagicDustAsync(folder);

            Directory.CreateDirectory(folder);

            return(new CoreNode(folder, builder));
        }
        private volatile bool _disposedValue = false;         // To detect redundant calls

        public RegTestFixture()
        {
            RuntimeParams.SetDataDir(Path.Combine(Tests.Global.Instance.DataDir, "RegTests", "Backend"));
            RuntimeParams.LoadAsync().GetAwaiter().GetResult();
            var hostedServices = new HostedServices();

            BackendRegTestNode = TestNodeBuilder.CreateAsync(hostedServices, callerFilePath: "RegTests", callerMemberName: "BitcoinCoreData").GetAwaiter().GetResult();

            var testnetBackendDir = EnvironmentHelpers.GetDataDir(Path.Combine("WalletWasabi", "Tests", "RegTests", "Backend"));

            IoHelpers.DeleteRecursivelyWithMagicDustAsync(testnetBackendDir).GetAwaiter().GetResult();
            Thread.Sleep(100);
            Directory.CreateDirectory(testnetBackendDir);
            Thread.Sleep(100);
            var config = new Config(
                BackendRegTestNode.RpcClient.Network,
                BackendRegTestNode.RpcClient.CredentialString.ToString(),
                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.ToFile();

            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.ToFile();

            var conf = new ConfigurationBuilder()
                       .AddInMemoryCollection(new[] { new KeyValuePair <string, string>("datadir", testnetBackendDir) })
                       .Build();

            BackendEndPoint = $"http://localhost:{new Random().Next(37130, 38000)}/";

            BackendHost = Host.CreateDefaultBuilder()
                          .ConfigureWebHostDefaults(webBuilder => webBuilder
                                                    .UseStartup <Startup>()
                                                    .UseConfiguration(conf)
                                                    .UseWebRoot("../../../../WalletWasabi.Backend/wwwroot")
                                                    .UseUrls(BackendEndPoint))
                          .Build();

            Global = (Backend.Global)BackendHost.Services.GetService(typeof(Backend.Global));
            Global.HostedServices = hostedServices;
            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)
        }
예제 #7
0
 private static async Task TryRemoveWorkingDirectoryAsync()
 {
     try
     {
         await IoHelpers.DeleteRecursivelyWithMagicDustAsync(WorkingDirectory);
     }
     catch (DirectoryNotFoundException)
     {
     }
 }
예제 #8
0
        private async Task <(string walletsPath, string walletsBackupPath)> CleanupWalletDirectoriesAsync(string baseDir)
        {
            var walletsPath       = Path.Combine(baseDir, WalletDirectories.WalletsDirName);
            var walletsBackupPath = Path.Combine(baseDir, WalletDirectories.WalletsBackupDirName);
            await IoHelpers.DeleteRecursivelyWithMagicDustAsync(walletsPath);

            await IoHelpers.DeleteRecursivelyWithMagicDustAsync(walletsBackupPath);

            return(walletsPath, walletsBackupPath);
        }
예제 #9
0
        private static void CreateDigests()
        {
            var tempDir = "DigestTempDir";

            IoHelpers.DeleteRecursivelyWithMagicDustAsync(tempDir).GetAwaiter();
            Directory.CreateDirectory(tempDir);

            var    torDaemonsDir = Path.Combine(LibraryProjectDirectory, "TorDaemons");
            string torWinZip     = Path.Combine(torDaemonsDir, "tor-win32.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(torWinZip, tempDir).GetAwaiter();
            File.Move(Path.Combine(tempDir, "Tor", "tor.exe"), Path.Combine(tempDir, "TorWin"));

            string torLinuxZip = Path.Combine(torDaemonsDir, "tor-linux64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(torLinuxZip, tempDir).GetAwaiter();
            File.Move(Path.Combine(tempDir, "Tor", "tor"), Path.Combine(tempDir, "TorLin"));

            string torOsxZip = Path.Combine(torDaemonsDir, "tor-osx64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(torOsxZip, tempDir).GetAwaiter();
            File.Move(Path.Combine(tempDir, "Tor", "tor"), Path.Combine(tempDir, "TorOsx"));

            string hwiSoftwareDir = Path.Combine(LibraryProjectDirectory, "Hwi", "Software");
            string hwiWinZip      = Path.Combine(hwiSoftwareDir, "hwi-win64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(hwiWinZip, tempDir).GetAwaiter();
            File.Move(Path.Combine(tempDir, "hwi.exe"), Path.Combine(tempDir, "HwiWin"));

            string hwiLinuxZip = Path.Combine(hwiSoftwareDir, "hwi-linux64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(hwiLinuxZip, tempDir).GetAwaiter();
            File.Move(Path.Combine(tempDir, "hwi"), Path.Combine(tempDir, "HwiLin"));

            string hwiOsxZip = Path.Combine(hwiSoftwareDir, "hwi-osx64.zip");

            IoHelpers.BetterExtractZipToDirectoryAsync(hwiOsxZip, tempDir).GetAwaiter();
            File.Move(Path.Combine(tempDir, "hwi"), Path.Combine(tempDir, "HwiOsx"));

            var tempDirInfo = new DirectoryInfo(tempDir);
            var binaries    = tempDirInfo.GetFiles();

            Console.WriteLine("Digests:");
            foreach (var file in binaries)
            {
                var filePath = file.FullName;
                var hash     = ByteHelpers.ToHex(IoHelpers.GetHashFile(filePath)).ToLowerInvariant();
                Console.WriteLine($"{file.Name} : {hash}");
            }

            IoHelpers.DeleteRecursivelyWithMagicDustAsync(tempDir).GetAwaiter();
        }
예제 #10
0
        public RegTestFixture()
        {
            BackendNodeBuilder = NodeBuilder.CreateAsync(nameof(RegTestFixture)).GetAwaiter().GetResult();
            BackendNodeBuilder.CreateNodeAsync().GetAwaiter().GetResult();
            BackendNodeBuilder.StartAllAsync().GetAwaiter().GetResult();
            BackendRegTestNode = BackendNodeBuilder.Nodes[0];

            var rpc = BackendRegTestNode.CreateRpcClient();
            var connectionString = new RPCCredentialString()
            {
                Server       = rpc.Address.AbsoluteUri,
                UserPassword = BackendRegTestNode.Creds
            }.ToString();

            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, IPAddress.Loopback.ToString(), IPAddress.Loopback.ToString(), BackendRegTestNode.Endpoint.Address.ToString(), Network.Main.DefaultPort, Network.TestNet.DefaultPort, BackendRegTestNode.Endpoint.Port);
            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}", nameof(Global));

            var delayTask = Task.Delay(3000);

            Task.WaitAny(delayTask, hostInitializationTask);             // Wait for server to initialize (Without this OSX CI will fail)
        }
예제 #11
0
 private static async Task TryRemoveWorkingDirectoryAsync()
 {
     try
     {
         await IoHelpers.DeleteRecursivelyWithMagicDustAsync(WorkingDirectory);
     }
     catch (DirectoryNotFoundException)
     {
     }
     catch (Exception ex)
     {
         Logger.LogError <NodeBuilder>(ex);
     }
 }
예제 #12
0
 public void Kill(bool cleanFolder = true)
 {
     lock (_l)
     {
         if (_process != null && !_process.HasExited)
         {
             _process.Kill();
             _process.WaitForExit();
         }
         State = CoreNodeState.Killed;
         if (cleanFolder)
         {
             IoHelpers.DeleteRecursivelyWithMagicDustAsync(Folder).GetAwaiter().GetResult();
         }
     }
 }
        private async Task <TransactionProcessor> CreateTransactionProcessorAsync([CallerMemberName] string callerName = "")
        {
            var keyManager = KeyManager.CreateNew(out _, "password");

            keyManager.AssertCleanKeysIndexed();

            var txStore = new AllTransactionStore();
            var dir     = Path.Combine(Global.Instance.DataDir, callerName, "TransactionStore");
            await IoHelpers.DeleteRecursivelyWithMagicDustAsync(dir);

            await txStore.InitializeAsync(dir, Network.RegTest);

            return(new TransactionProcessor(
                       txStore,
                       keyManager,
                       Money.Coins(0.0001m)));
        }
예제 #14
0
        public static async Task <NodeBuilder> CreateAsync([CallerMemberName] string caller = null, string version = "0.16.0")
        {
            var directory = Path.Combine(SharedFixture.DataDir, caller);

            version = version ?? "0.16.0";
            var path = await EnsureDownloadedAsync(version);

            try
            {
                await IoHelpers.DeleteRecursivelyWithMagicDustAsync(directory);
            }
            catch (DirectoryNotFoundException)
            {
            }
            Directory.CreateDirectory(directory);
            return(new NodeBuilder(directory, path));
        }
예제 #15
0
        public async Task StopAsync()
        {
            try
            {
                using (await KillerLock.LockAsync())
                {
                    await RpcClient.StopAsync();

                    using var timeout = new CancellationTokenSource(20000);
                    await Process.WaitForExitAsync(timeout.Token);

                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(DataDir);
                }
            }
            catch (Exception ex)
            {
                Logging.Logger.LogWarning(ex);
            }
        }
예제 #16
0
        public async Task <CoreNode> CreateNodeAsync(bool start = false)
        {
            var child = Path.Combine(_root, _last.ToString());

            _last++;
            try
            {
                await IoHelpers.DeleteRecursivelyWithMagicDustAsync(child);
            }
            catch (DirectoryNotFoundException)
            {
            }
            var node = await CoreNode.CreateAsync(child, this);

            Nodes.Add(node);
            if (start)
            {
                await node.StartAsync();
            }
            return(node);
        }
예제 #17
0
        private static async Task <string> EnsureDownloadedAsync(string version)
        {
            //is a file
            if (version.Length >= 2 && version[1] == ':')
            {
                return(version);
            }

            string zip;
            string bitcoind;
            string bitcoindFolderName = $"bitcoin-{version}";

            // Remove old bitcoind folders.
            IEnumerable <string> existingBitcoindFolderPaths = Directory.EnumerateDirectories(Global.Instance.DataDir, "bitcoin-*", SearchOption.TopDirectoryOnly);

            foreach (string dirPath in existingBitcoindFolderPaths)
            {
                string dirName = Path.GetFileName(dirPath);
                if (bitcoindFolderName != dirName)
                {
                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(dirPath);
                }
            }

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                bitcoind = Path.Combine(Global.Instance.DataDir, bitcoindFolderName, "bin", "bitcoind.exe");
                if (File.Exists(bitcoind))
                {
                    return(bitcoind);
                }

                zip = Path.Combine(Global.Instance.DataDir, $"bitcoin-{version}-win64.zip");
                string url = string.Format("https://bitcoincore.org/bin/bitcoin-core-{0}/" + Path.GetFileName(zip), version);
                using (var client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromMinutes(10.0);
                    var data = await client.GetByteArrayAsync(url);

                    await File.WriteAllBytesAsync(zip, data);

                    ZipFile.ExtractToDirectory(zip, new FileInfo(zip).Directory.FullName);
                }
            }
            else
            {
                bitcoind = Path.Combine(Global.Instance.DataDir, bitcoindFolderName, "bin", "bitcoind");
                if (File.Exists(bitcoind))
                {
                    return(bitcoind);
                }

                zip = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
                                        ? Path.Combine(Global.Instance.DataDir, $"bitcoin-{version}-x86_64-linux-gnu.tar.gz")
                                        : Path.Combine(Global.Instance.DataDir, $"bitcoin-{version}-osx64.tar.gz");

                string url = string.Format("https://bitcoincore.org/bin/bitcoin-core-{0}/" + Path.GetFileName(zip), version);
                using (var client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromMinutes(10.0);
                    var data = await client.GetByteArrayAsync(url);

                    await File.WriteAllBytesAsync(zip, data);

                    using (var process = Process.Start("tar", "-zxvf " + zip + " -C " + Global.Instance.DataDir))
                    {
                        process.WaitForExit();
                    }
                }
            }
            File.Delete(zip);
            return(bitcoind);
        }
예제 #18
0
        public static async Task <CoreNode> CreateAsync(string dataDir)
        {
            var coreNode = new CoreNode();

            coreNode.DataDir = Guard.NotNullOrEmptyOrWhitespace(nameof(dataDir), dataDir);

            var configPath = Path.Combine(coreNode.DataDir, "bitcoin.conf");

            if (File.Exists(configPath))
            {
                var foundConfig = await NodeConfigParameters.LoadAsync(configPath);

                var rpcPortString = foundConfig["regtest.rpcport"];
                var rpcUser       = foundConfig["regtest.rpcuser"];
                var rpcPassword   = foundConfig["regtest.rpcpassword"];
                var pidFileName   = foundConfig["regtest.pid"];
                var credentials   = new NetworkCredential(rpcUser, rpcPassword);
                try
                {
                    var rpc = new RPCClient(credentials, new Uri("http://127.0.0.1:" + rpcPortString + "/"), Network.RegTest);
                    await rpc.StopAsync();

                    var pidFile = Path.Combine(coreNode.DataDir, "regtest", pidFileName);
                    if (File.Exists(pidFile))
                    {
                        var pid = await File.ReadAllTextAsync(pidFile);

                        using var process = Process.GetProcessById(int.Parse(pid));
                        await process.WaitForExitAsync(CancellationToken.None);
                    }
                    else
                    {
                        var allProcesses      = Process.GetProcesses();
                        var bitcoindProcesses = allProcesses.Where(x => x.ProcessName.Contains("bitcoind"));
                        if (bitcoindProcesses.Count() == 1)
                        {
                            var bitcoind = bitcoindProcesses.First();
                            await bitcoind.WaitForExitAsync(CancellationToken.None);
                        }
                    }
                }
                catch (Exception)
                {
                }
            }

            await IoHelpers.DeleteRecursivelyWithMagicDustAsync(coreNode.DataDir);

            IoHelpers.EnsureDirectoryExists(coreNode.DataDir);

            var pass  = Encoders.Hex.EncodeData(RandomUtils.GetBytes(20));
            var creds = new NetworkCredential(pass, pass);

            var portArray = new int[2];
            var i         = 0;

            while (i < portArray.Length)
            {
                var port = RandomUtils.GetUInt32() % 4000;
                port += 10000;
                if (portArray.Any(p => p == port))
                {
                    continue;
                }

                try
                {
                    var listener = new TcpListener(IPAddress.Loopback, (int)port);
                    listener.Start();
                    listener.Stop();
                    portArray[i] = (int)port;
                    i++;
                }
                catch (SocketException)
                {
                }
            }

            var p2pPort = portArray[0];
            var rpcPort = portArray[1];

            coreNode.P2pEndPoint = new IPEndPoint(IPAddress.Loopback, p2pPort);
            coreNode.RpcEndPoint = new IPEndPoint(IPAddress.Loopback, rpcPort);

            coreNode.RpcClient = new RPCClient($"{creds.UserName}:{creds.Password}", coreNode.RpcEndPoint.ToString(rpcPort), Network.RegTest);

            var config = new NodeConfigParameters
            {
                { "regtest", "1" },
                { "regtest.rest", "1" },
                { "regtest.listenonion", "0" },
                { "regtest.server", "1" },
                { "regtest.txindex", "1" },
                { "regtest.rpcuser", coreNode.RpcClient.CredentialString.UserPassword.UserName },
                { "regtest.rpcpassword", coreNode.RpcClient.CredentialString.UserPassword.Password },
                { "regtest.whitebind", "127.0.0.1:" + p2pPort.ToString() },
                { "regtest.rpcport", coreNode.RpcEndPoint.GetPortOrDefault().ToString() },
                { "regtest.printtoconsole", "0" },               // Set it to one if do not mind loud debug logs
                { "regtest.keypool", "10" },
                { "regtest.pid", "bitcoind.pid" }
            };

            await File.WriteAllTextAsync(configPath, config.ToString());

            using (await coreNode.KillerLock.LockAsync())
            {
                coreNode.Bridge  = new BitcoindProcessBridge();
                coreNode.Process = coreNode.Bridge.Start($"-conf=bitcoin.conf -datadir={coreNode.DataDir} -debug=1", false);
                string pidFile = Path.Combine(coreNode.DataDir, "regtest", "bitcoind.pid");
                if (!File.Exists(pidFile))
                {
                    Directory.CreateDirectory(Path.Combine(coreNode.DataDir, "regtest"));
                    await File.WriteAllTextAsync(pidFile, coreNode.Process.Id.ToString());
                }
            }
            while (true)
            {
                try
                {
                    await coreNode.RpcClient.GetBlockHashAsync(0);

                    break;
                }
                catch
                {
                }
                if (coreNode.Process is null || coreNode.Process.HasExited)
                {
                    break;
                }
            }

            return(coreNode);
        }
예제 #19
0
        private static void Main(string[] args)
        {
            // 0. Dump Client version (or else wrong .msi will be created) - Helpers.Constants.ClientVersion
            // 1. Publish with Packager.
            // 2. Build WIX project with Release and x64 configuration.
            // 3. Sign with Packager, set restore true so the password won't be kept.
            var doPublish         = true;
            var doSign            = false;
            var doRestoreThisFile = false;
            var pfxPassword       = "******";

            string pfxPath = "C:\\digicert.pfx";
            string packagerProjectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\"));
            string solutionDirectory        = Path.GetFullPath(Path.Combine(packagerProjectDirectory, "..\\"));
            string guiProjectDirectory      = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.Gui\\"));
            string libraryProjectDirectory  = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi\\"));
            string wixProjectDirectory      = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.WindowsInstaller\\"));
            string binDistDirectory         = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\dist"));

            Console.WriteLine($"{nameof(solutionDirectory)}:\t\t{solutionDirectory}");
            Console.WriteLine($"{nameof(packagerProjectDirectory)}:\t{packagerProjectDirectory}");
            Console.WriteLine($"{nameof(guiProjectDirectory)}:\t\t{guiProjectDirectory}");
            Console.WriteLine($"{nameof(libraryProjectDirectory)}:\t\t{libraryProjectDirectory}");
            Console.WriteLine($"{nameof(wixProjectDirectory)}:\t\t{wixProjectDirectory}");
            Console.WriteLine($"{nameof(binDistDirectory)}:\t\t{binDistDirectory}");

            string versionPrefix  = Helpers.Constants.ClientVersion.ToString();
            string executableName = "wassabee";

            Console.WriteLine();
            Console.WriteLine($"{nameof(versionPrefix)}:\t\t\t{versionPrefix}");
            Console.WriteLine($"{nameof(executableName)}:\t\t\t{executableName}");

            // https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog
            // BOTTLENECKS:
            // Tor - win-32, linux-32, osx-64
            // .NET Core - win-32, linux-64, osx-64
            // Avalonia - win7-32, linux-64, osx-64
            // We'll only support x64, if someone complains, we can come back to it.
            // For 32 bit Windows there needs to be a lot of WIX configuration to be done.
            var targets = new List <string>
            {
                "win7-x64",
                "linux-x64",
                "osx-x64"
            };

            Console.WriteLine();
            Console.Write($"{nameof(targets)}:\t\t\t");
            targets.ForEach(x =>
            {
                if (targets.Last() != x)
                {
                    Console.Write($"{x}, ");
                }
                else
                {
                    Console.Write(x);
                }
            });
            Console.WriteLine();

            if (doPublish)
            {
                if (Directory.Exists(binDistDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(binDistDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {binDistDirectory}");
                }

                var psiBuild = new ProcessStartInfo
                {
                    FileName = "cmd",
                    RedirectStandardInput = true,
                    WorkingDirectory      = guiProjectDirectory
                };
                using (var pBuild = Process.Start(psiBuild))
                {
                    pBuild.StandardInput.WriteLine("dotnet clean --configuration Release && exit");
                    pBuild.WaitForExit();
                }

                var guiBinReleaseDirectory     = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\Release"));
                var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(libraryProjectDirectory, "bin\\Release"));
                if (Directory.Exists(guiBinReleaseDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {guiBinReleaseDirectory}");
                }
                if (Directory.Exists(libraryBinReleaseDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {libraryBinReleaseDirectory}");
                }

                foreach (string target in targets)
                {
                    string currentBinDistDirectory;
                    string publishedFolder = Path.Combine(binDistDirectory, target);
                    string macWasabiAppDir = Path.Combine(publishedFolder, "Wasabi Wallet.App");
                    string macContentsDir  = Path.Combine(macWasabiAppDir, "Contents");
                    if (target.StartsWith("osx"))
                    {
                        currentBinDistDirectory = Path.GetFullPath(Path.Combine(macContentsDir, "MacOS"));
                    }
                    else
                    {
                        currentBinDistDirectory = publishedFolder;
                    }
                    Console.WriteLine();
                    Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}");

                    Console.WriteLine();
                    if (!Directory.Exists(currentBinDistDirectory))
                    {
                        Directory.CreateDirectory(currentBinDistDirectory);
                        Console.WriteLine($"Created {currentBinDistDirectory}");
                    }

                    var psiClean = new ProcessStartInfo
                    {
                        FileName         = "dotnet",
                        Arguments        = $"clean",
                        WorkingDirectory = guiProjectDirectory
                    };
                    using (var pClean = Process.Start(psiClean))
                    {
                        pClean.WaitForExit();
                    }

                    // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21
                    // -c|--configuration {Debug|Release}
                    //		Defines the build configuration. The default value is Debug.
                    // --force
                    //		Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file.
                    // -o|--output <OUTPUT_DIRECTORY>
                    //		Specifies the path for the output directory.
                    //		If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or
                    //		./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment.
                    //		If the path is relative, the output directory generated is relative to the project file location, not to the current working directory.
                    // --self-contained
                    //		Publishes the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine.
                    //		If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment.
                    // -r|--runtime <RUNTIME_IDENTIFIER>
                    //		Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD).
                    //		For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD).
                    // --version-suffix <VERSION_SUFFIX>
                    //		Defines the version suffix to replace the asterisk (*) in the version field of the project file.
                    // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x
                    // --disable-parallel
                    //		Disables restoring multiple projects in parallel.
                    // --no-cache
                    //		Specifies to not cache packages and HTTP requests.
                    // https://github.com/dotnet/docs/issues/7568
                    // /p:Version=1.2.3.4
                    //		"dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4
                    var psiPublish = new ProcessStartInfo
                    {
                        FileName         = "dotnet",
                        Arguments        = $"publish --configuration Release --force --output \"{currentBinDistDirectory}\" --self-contained true --runtime \"{target}\" /p:VersionPrefix={versionPrefix} --disable-parallel --no-cache",
                        WorkingDirectory = guiProjectDirectory
                    };
                    using (var pPublish = Process.Start(psiPublish))
                    {
                        pPublish.WaitForExit();
                    }

                    // Rename the final exe.
                    string oldExecutablePath;
                    string newExecutablePath;
                    if (target.StartsWith("win"))
                    {
                        oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe");
                        newExecutablePath = Path.Combine(currentBinDistDirectory, $"{executableName}.exe");
                    }
                    else                     // Linux & OSX
                    {
                        oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui");
                        newExecutablePath = Path.Combine(currentBinDistDirectory, executableName);
                    }
                    File.Move(oldExecutablePath, newExecutablePath);

                    if (target.StartsWith("win"))
                    {
                        var psiEditbin = new ProcessStartInfo
                        {
                            FileName         = "editbin",
                            Arguments        = $"\"{newExecutablePath}\" /SUBSYSTEM:WINDOWS",
                            WorkingDirectory = currentBinDistDirectory
                        };
                        using (var pEditbin = Process.Start(psiEditbin))
                        {
                            pEditbin.WaitForExit();
                        }

                        var icoPath   = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.ico");
                        var psiRcedit = new ProcessStartInfo
                        {
                            FileName         = "rcedit",
                            Arguments        = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{versionPrefix}\" --set-product-version \"{versionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"",
                            WorkingDirectory = currentBinDistDirectory
                        };
                        using (var pRcedit = Process.Start(psiRcedit))
                        {
                            pRcedit.WaitForExit();
                        }
                    }
                    else if (target.StartsWith("osx"))
                    {
                        string resourcesDir = Path.Combine(macContentsDir, "Resources");
                        string infoFilePath = Path.Combine(macContentsDir, "Info.plist");

                        Directory.CreateDirectory(resourcesDir);
                        var iconpath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.icns");
                        File.Copy(iconpath, Path.Combine(resourcesDir, "WasabiLogo.icns"));

                        string infoContent = $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version = ""1.0"">
<dict>
	<key>LSMinimumSystemVersion</key>
	<string>10.12</string>

	<key>LSArchitecturePriority</key>
	<array>
		<string>x86_64</string>
	</array>

	<key>CFBundleIconFile</key>
	<string>WasabiLogo.icns</string>

	<key>CFBundlePackageType</key>
	<string>APPL</string>

	<key>CFBundleShortVersionString</key>
	<string>{versionPrefix}</string>

	<key>CFBundleVersion</key>
	<string>{versionPrefix}</string>

	<key>CFBundleExecutable</key>
	<string>wassabee</string>

	<key>CFBundleName</key>
	<string>Wasabi Wallet</string>

	<key>CFBundleIdentifier</key>
	<string>zksnacks.wasabiwallet</string>

	<key>NSHighResolutionCapable</key>
	<true/>

	<key>NSAppleScriptEnabled</key>
	<true/>

	<key>LSApplicationCategoryType</key>
	<string>public.app-category.finance</string>

	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
</dict>
</plist>
";
                        File.WriteAllText(infoFilePath, infoContent);

                        var psiCreateSymLink = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = publishedFolder
                        };
                        using (var createSymLinkProcess = Process.Start(psiCreateSymLink))
                        {
                            createSymLinkProcess.StandardInput.WriteLine($"wsl ln -s /Applications && exit");
                            createSymLinkProcess.WaitForExit();
                        }

                        //how to generate .DS_Store file - https://github.com/zkSNACKs/WalletWasabi/pull/928/commits/e38ed672dee25f6e45a3eb16584887cc6d48c4e6
                        var dmgContentDir = Path.Combine(packagerProjectDirectory, "Content", "Osx");
                        IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentDir), new DirectoryInfo(publishedFolder));

                        var psiGenIsoImage = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };

                        string uncompressedDmgFileName = $"Wasabi-uncompressed.dmg";
                        string uncompressedDmgFilePath = Path.Combine(binDistDirectory, uncompressedDmgFileName);
                        string dmgFileName             = $"Wasabi-{versionPrefix}.dmg";
                        using (var genIsoImageProcess = Process.Start(psiGenIsoImage))
                        {
                            // http://www.nathancoulson.com/proj_cross_tools.php
                            // -D: Do not use deep directory relocation, and instead just pack them in the way we see them
                            // -V: Volume Label
                            // -no-pad: Do not pad the end by 150 sectors (300kb). As it is not a cd image, not required
                            // -apple -r: Creates a .dmg image
                            genIsoImageProcess.StandardInput.WriteLine($"wsl genisoimage -D -V \"Wasabi Wallet\" -no-pad -apple -r -o \"{uncompressedDmgFileName}\" \"{new DirectoryInfo(publishedFolder).Name}\" && exit");
                            genIsoImageProcess.WaitForExit();
                        }
                        // cd ~
                        // git clone https://github.com/planetbeing/libdmg-hfsplus.git && cd libdmg-hfsplus
                        // https://github.com/planetbeing/libdmg-hfsplus/issues/14
                        // mkdir build && cd build
                        // sudo apt-get install zlib1g-dev
                        // cmake ..
                        // cd build
                        // sudo apt-get install libssl1.0-dev
                        // cmake ..
                        // cd ~/libdmg-hfsplus/build/
                        // make
                        var psiDmg = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        using (var dmgProcess = Process.Start(psiDmg))
                        {
                            dmgProcess.StandardInput.WriteLine($"wsl ~/libdmg-hfsplus/build/dmg/./dmg dmg \"{uncompressedDmgFileName}\" \"{dmgFileName}\" && exit");
                            dmgProcess.WaitForExit();
                        }
                        // In case compression above doesn't work:
                        //var psiBzip = new ProcessStartInfo
                        //{
                        //	FileName = "cmd",
                        //	RedirectStandardInput = true,
                        //	WorkingDirectory = binDistDirectory
                        //};
                        //var bzipProcess = Process.Start(psiBzip);
                        //bzipProcess.StandardInput.WriteLine($"wsl bzip2 \"{uncompressedDmgFileName}\" && exit");
                        //bzipProcess.WaitForExit();

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        File.Delete(uncompressedDmgFilePath);

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                    else if (target.StartsWith("linux"))
                    {
                        Console.WriteLine("Create Linux .tar.gz");
                        if (!Directory.Exists(publishedFolder))
                        {
                            throw new Exception($"{publishedFolder} doesn't exist.");
                        }
                        var newFolderName = $"WasabiLinux-{versionPrefix}";
                        var newFolderPath = Path.Combine(binDistDirectory, newFolderName);
                        Directory.Move(publishedFolder, newFolderPath);
                        publishedFolder = newFolderPath;

                        var psiTar = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        using (var tarProcess = Process.Start(psiTar))
                        {
                            tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit");
                            tarProcess.WaitForExit();
                        }

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                }
            }

            if (doSign is true)
            {
                foreach (string target in targets)
                {
                    if (target.StartsWith("win", StringComparison.OrdinalIgnoreCase))
                    {
                        string publishedFolder = Path.Combine(binDistDirectory, target);

                        Console.WriteLine("Move created .msi");
                        var msiPath = Path.Combine(wixProjectDirectory, @"bin\Release\Wasabi.msi");
                        if (!File.Exists(msiPath))
                        {
                            throw new Exception(".msi doesn't exist. Expected path: Wasabi.msi.");
                        }
                        var msiFileName = Path.GetFileNameWithoutExtension(msiPath);
                        var newMsiPath  = Path.Combine(binDistDirectory, $"{msiFileName}-{versionPrefix}.msi");
                        File.Move(msiPath, newMsiPath);

                        // Sign code with digicert.
                        var psiSigntool = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        using (var signToolProcess = Process.Start(psiSigntool))
                        {
                            signToolProcess.StandardInput.WriteLine($"signtool sign /d \"Wasabi Wallet\" /f \"{pfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit");
                            signToolProcess.WaitForExit();
                        }

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                }

                Console.WriteLine("Signing final files...");
                var finalFiles = Directory.GetFiles(binDistDirectory);

                foreach (var finalFile in finalFiles)
                {
                    var psiSignProcess = new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory      = binDistDirectory
                    };
                    using (var signProcess = Process.Start(psiSignProcess))
                    {
                        signProcess.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit");
                        signProcess.WaitForExit();
                    }

                    var psiRestoreHeat = new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory      = wixProjectDirectory
                    };
                    using (var restoreHeatProcess = Process.Start(psiRestoreHeat))
                    {
                        restoreHeatProcess.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit");
                        restoreHeatProcess.WaitForExit();
                    }

                    if (doRestoreThisFile)
                    {
                        var psiRestoreThisFile = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = packagerProjectDirectory
                        };
                        using (var restoreThisFileProcess = Process.Start(psiRestoreThisFile))
                        {
                            restoreThisFileProcess.StandardInput.WriteLine($"git checkout -- Program.cs && exit");
                            restoreThisFileProcess.WaitForExit();
                        }
                    }
                }

                IoHelpers.OpenFolderInFileExplorer(binDistDirectory);
                return;                 // No need for readkey here.
            }
        }
예제 #20
0
 private async Task CleanFolderAsync()
 {
     await IoHelpers.DeleteRecursivelyWithMagicDustAsync(Folder);
 }
예제 #21
0
        private static void Publish()
        {
            if (Directory.Exists(BinDistDirectory))
            {
                IoHelpers.DeleteRecursivelyWithMagicDustAsync(BinDistDirectory).GetAwaiter().GetResult();
                Console.WriteLine($"Deleted {BinDistDirectory}");
            }

            using (var process = Process.Start(new ProcessStartInfo
            {
                FileName = "cmd",
                RedirectStandardInput = true,
                WorkingDirectory = GuiProjectDirectory
            }))
            {
                process.StandardInput.WriteLine("dotnet clean --configuration Release && exit");
                process.WaitForExit();
            }

            var guiBinReleaseDirectory     = Path.GetFullPath(Path.Combine(GuiProjectDirectory, "bin\\Release"));
            var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(LibraryProjectDirectory, "bin\\Release"));

            if (Directory.Exists(guiBinReleaseDirectory))
            {
                IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult();
                Console.WriteLine($"Deleted {guiBinReleaseDirectory}");
            }
            if (Directory.Exists(libraryBinReleaseDirectory))
            {
                IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult();
                Console.WriteLine($"Deleted {libraryBinReleaseDirectory}");
            }

            foreach (string target in Targets)
            {
                string publishedFolder         = Path.Combine(BinDistDirectory, target);
                string currentBinDistDirectory = publishedFolder;

                Console.WriteLine();
                Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}");

                Console.WriteLine();
                if (!Directory.Exists(currentBinDistDirectory))
                {
                    Directory.CreateDirectory(currentBinDistDirectory);
                    Console.WriteLine($"Created {currentBinDistDirectory}");
                }

                using (var process = Process.Start(new ProcessStartInfo
                {
                    FileName = "dotnet",
                    Arguments = $"clean",
                    WorkingDirectory = GuiProjectDirectory
                }))
                {
                    process.WaitForExit();
                }

                // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21
                // -c|--configuration {Debug|Release}
                //		Defines the build configuration. The default value is Debug.
                // --force
                //		Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file.
                // -o|--output <OUTPUT_DIRECTORY>
                //		Specifies the path for the output directory.
                //		If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or
                //		./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment.
                //		If the path is relative, the output directory generated is relative to the project file location, not to the current working directory.
                // --self-contained
                //		Publishes the .NET Core runtime with your application so the runtime does not need to be installed on the target machine.
                //		If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment.
                // -r|--runtime <RUNTIME_IDENTIFIER>
                //		Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD).
                //		For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD).
                // --version-suffix <VERSION_SUFFIX>
                //		Defines the version suffix to replace the asterisk (*) in the version field of the project file.
                // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x
                // --disable-parallel
                //		Disables restoring multiple projects in parallel.
                // --no-cache
                //		Specifies to not cache packages and HTTP requests.
                // https://github.com/dotnet/docs/issues/7568
                // /p:Version=1.2.3.4
                //		"dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4
                using (var process = Process.Start(new ProcessStartInfo
                {
                    FileName = "dotnet",
                    Arguments = $"publish --configuration Release --force --output \"{currentBinDistDirectory}\" --self-contained true --runtime \"{target}\" /p:VersionPrefix={VersionPrefix} --disable-parallel --no-cache /p:DebugType=none /p:DebugSymbols=false /p:ErrorReport=none /p:DocumentationFile=\"\" /p:Deterministic=true",
                    WorkingDirectory = GuiProjectDirectory
                }))
                {
                    process.WaitForExit();
                }

                Tools.ClearSha512Tags(currentBinDistDirectory);

                // Remove Tor binaries that are not relevant to the platform.
                var torFolder   = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "TorDaemons"));
                var toNotRemove = "";
                if (target.StartsWith("win"))
                {
                    toNotRemove = "win";
                }
                else if (target.StartsWith("linux"))
                {
                    toNotRemove = "lin";
                }
                else if (target.StartsWith("osx"))
                {
                    toNotRemove = "osx";
                }

                foreach (var file in torFolder.EnumerateFiles())
                {
                    if (!file.Name.Contains("data", StringComparison.OrdinalIgnoreCase) && !file.Name.Contains(toNotRemove, StringComparison.OrdinalIgnoreCase))
                    {
                        File.Delete(file.FullName);
                    }
                }

                // Remove binaries that are not relevant to the platform.
                var binaryFolder = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "Microservices", "Binaries"));

                foreach (var dir in binaryFolder.EnumerateDirectories())
                {
                    if (!dir.Name.Contains(toNotRemove, StringComparison.OrdinalIgnoreCase))
                    {
                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(dir.FullName).GetAwaiter().GetResult();
                    }
                }

                // Rename the final exe.
                string oldExecutablePath;
                string newExecutablePath;
                if (target.StartsWith("win"))
                {
                    oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe");
                    newExecutablePath = Path.Combine(currentBinDistDirectory, $"{ExecutableName}.exe");
                }
                else                 // Linux & OSX
                {
                    oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui");
                    newExecutablePath = Path.Combine(currentBinDistDirectory, ExecutableName);
                }
                File.Move(oldExecutablePath, newExecutablePath);

                long installedSizeKb = Tools.DirSize(new DirectoryInfo(publishedFolder)) / 1000;

                if (target.StartsWith("win"))
                {
                    var icoPath = Path.Combine(GuiProjectDirectory, "Assets", "WasabiLogo.ico");
                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "rcedit",                         // https://github.com/electron/rcedit/
                        Arguments = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{VersionPrefix}\" --set-product-version \"{VersionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"",
                        WorkingDirectory = currentBinDistDirectory
                    }))
                    {
                        process.WaitForExit();
                    }

                    var daemonExePath = newExecutablePath[0..^ 4] + "d.exe";
예제 #22
0
        private static void Main(string[] args)
        {
            // 0. Dump Client version (or else wrong .msi will be created) - Helpers.Constants.ClientVersion
            // 1. Publish with Packager.
            // 2. Build WIX project with Release and x64 configuration.
            // 3. Sign with Packager.
            bool doPublish = true;
            bool doSign    = false;

            string packagerProjectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\"));
            string solutionDirectory        = Path.GetFullPath(Path.Combine(packagerProjectDirectory, "..\\"));
            string guiProjectDirectory      = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.Gui\\"));
            string libraryProjectDirectory  = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi\\"));
            string wixProjectDirectory      = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.WindowsInstaller\\"));
            string binDistDirectory         = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\dist"));

            Console.WriteLine($"{nameof(solutionDirectory)}:\t\t{solutionDirectory}");
            Console.WriteLine($"{nameof(packagerProjectDirectory)}:\t{packagerProjectDirectory}");
            Console.WriteLine($"{nameof(guiProjectDirectory)}:\t\t{guiProjectDirectory}");
            Console.WriteLine($"{nameof(libraryProjectDirectory)}:\t\t{libraryProjectDirectory}");
            Console.WriteLine($"{nameof(wixProjectDirectory)}:\t\t{wixProjectDirectory}");
            Console.WriteLine($"{nameof(binDistDirectory)}:\t\t{binDistDirectory}");

            string versionPrefix  = Helpers.Constants.ClientVersion.ToString();
            string executableName = "wassabee";

            Console.WriteLine();
            Console.WriteLine($"{nameof(versionPrefix)}:\t\t\t{versionPrefix}");
            Console.WriteLine($"{nameof(executableName)}:\t\t\t{executableName}");

            // https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog
            // BOTTLENECKS:
            // Tor - win-32, linux-32, osx-64
            // .NET Core - win-32, linux-64, osx-64
            // Avalonia - win7-32, linux-64, osx-64
            // We'll only support x64, if someone complains, we can come back to it.
            // For 32 bit Windows there needs to be a lot of WIX configuration to be done.
            var targets = new List <string>
            {
                "win7-x64",
                "linux-x64",
                "osx-x64"
            };

            Console.WriteLine();
            Console.Write($"{nameof(targets)}:\t\t\t");
            targets.ForEach(x =>
            {
                if (targets.Last() != x)
                {
                    Console.Write($"{x}, ");
                }
                else
                {
                    Console.Write(x);
                }
            });
            Console.WriteLine();

            if (doPublish)
            {
                if (Directory.Exists(binDistDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(binDistDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {binDistDirectory}");
                }

                var psiBuild = new ProcessStartInfo
                {
                    FileName = "cmd",
                    RedirectStandardInput = true,
                    WorkingDirectory      = guiProjectDirectory
                };
                var pBuild = Process.Start(psiBuild);
                pBuild.StandardInput.WriteLine("dotnet clean --configuration Release && exit");
                pBuild.WaitForExit();

                var guiBinReleaseDirectory     = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\Release"));
                var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(libraryProjectDirectory, "bin\\Release"));
                if (Directory.Exists(guiBinReleaseDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {guiBinReleaseDirectory}");
                }
                if (Directory.Exists(libraryBinReleaseDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {libraryBinReleaseDirectory}");
                }

                foreach (string target in targets)
                {
                    string currentBinDistDirectory = Path.GetFullPath(Path.Combine(binDistDirectory, target));
                    Console.WriteLine();
                    Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}");

                    Console.WriteLine();
                    if (!Directory.Exists(currentBinDistDirectory))
                    {
                        Directory.CreateDirectory(currentBinDistDirectory);
                        Console.WriteLine($"Created {currentBinDistDirectory}");
                    }

                    // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21
                    // -c|--configuration {Debug|Release}
                    //		Defines the build configuration. The default value is Debug.
                    // --force
                    //		Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file.
                    // -o|--output <OUTPUT_DIRECTORY>
                    //		Specifies the path for the output directory.
                    //		If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or
                    //		./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment.
                    //		If the path is relative, the output directory generated is relative to the project file location, not to the current working directory.
                    // --self-contained
                    //		Publishes the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine.
                    //		If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment.
                    // -r|--runtime <RUNTIME_IDENTIFIER>
                    //		Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD).
                    //		For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD).
                    // --version-suffix <VERSION_SUFFIX>
                    //		Defines the version suffix to replace the asterisk (*) in the version field of the project file.
                    // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x
                    // --disable-parallel
                    //		Disables restoring multiple projects in parallel.
                    // --no-cache
                    //		Specifies to not cache packages and HTTP requests.
                    // https://github.com/dotnet/docs/issues/7568
                    // /p:Version=1.2.3.4
                    //		"dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4
                    var psiPublish = new ProcessStartInfo
                    {
                        FileName         = "dotnet",
                        Arguments        = $"publish --configuration Release --force --output {currentBinDistDirectory} --self-contained true --runtime {target} /p:VersionPrefix={versionPrefix} --disable-parallel --no-cache",
                        WorkingDirectory = guiProjectDirectory
                    };
                    var pPublish = Process.Start(psiPublish);
                    pPublish.WaitForExit();

                    // Rename the final exe.
                    string oldExecutablePath;
                    string newExecutablePath;
                    if (target.StartsWith("win"))
                    {
                        oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe");
                        newExecutablePath = Path.Combine(currentBinDistDirectory, $"{executableName}.exe");
                    }
                    else                     // Linux & OSX
                    {
                        oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui");
                        newExecutablePath = Path.Combine(currentBinDistDirectory, executableName);
                    }
                    File.Move(oldExecutablePath, newExecutablePath);

                    if (target.StartsWith("win"))
                    {
                        var psiEditbin = new ProcessStartInfo
                        {
                            FileName         = "editbin",
                            Arguments        = $"\"{newExecutablePath}\" /SUBSYSTEM:WINDOWS",
                            WorkingDirectory = currentBinDistDirectory
                        };
                        var pEditbin = Process.Start(psiEditbin);
                        pEditbin.WaitForExit();

                        var icoPath   = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.ico");
                        var psiRcedit = new ProcessStartInfo
                        {
                            FileName         = "rcedit",
                            Arguments        = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{versionPrefix}\" --set-product-version \"{versionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"",
                            WorkingDirectory = currentBinDistDirectory
                        };
                        var pRcedit = Process.Start(psiRcedit);
                        pRcedit.WaitForExit();
                    }
                }
            }

            if (doSign is true)
            {
                foreach (string target in targets)
                {
                    var publishedFolder = Path.Combine(binDistDirectory, $"{target}");

                    if (target.StartsWith("win", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("Move created .msi");
                        var msiPath = Path.Combine(wixProjectDirectory, @"bin\Release\WasabiInstaller.msi");
                        if (!File.Exists(msiPath))
                        {
                            throw new Exception(".msi doesn't exist. Expected path: WasabiInstaller.msi.");
                        }
                        var msiFileName = Path.GetFileName(msiPath);
                        var newMsiPath  = Path.Combine(binDistDirectory, msiFileName);
                        File.Move(msiPath, newMsiPath);
                    }
                    else if (target.StartsWith("linux", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("Create Linux .tar.gz");
                        if (!Directory.Exists(publishedFolder))
                        {
                            throw new Exception($"{publishedFolder} doesn't exist.");
                        }
                        var newFolderName = "WasabiLinux";
                        var newFolderPath = Path.Combine(binDistDirectory, newFolderName);
                        Directory.Move(publishedFolder, newFolderPath);
                        publishedFolder = newFolderPath;

                        var psiTar = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        var tarProcess = Process.Start(psiTar);
                        tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit");
                        tarProcess.WaitForExit();
                    }
                    else                     // if (target.StartsWith("osx", StringComparison.OrdinalIgnoreCase))
                    {
                        Console.WriteLine("Create OSX .tar.gz");
                        if (!Directory.Exists(publishedFolder))
                        {
                            throw new Exception($"{publishedFolder} doesn't exist.");
                        }
                        var newFolderName = "WasabiOsx";
                        var newFolderPath = Path.Combine(binDistDirectory, newFolderName);
                        Directory.Move(publishedFolder, newFolderPath);
                        publishedFolder = newFolderPath;

                        var psiTar = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        var tarProcess = Process.Start(psiTar);
                        tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit");
                        tarProcess.WaitForExit();
                    }

                    if (Directory.Exists(publishedFolder))
                    {
                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                }

                Console.WriteLine("Signing final files...");
                var finalFiles = Directory.GetFiles(binDistDirectory);

                foreach (var finalFile in finalFiles)
                {
                    var psiSignProcess = new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory      = binDistDirectory
                    };
                    var signProcess = Process.Start(psiSignProcess);
                    signProcess.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit");
                    signProcess.WaitForExit();

                    var psiRestoreHeat = new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory      = wixProjectDirectory
                    };
                    var restoreHeatProcess = Process.Start(psiRestoreHeat);
                    restoreHeatProcess.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit");
                    restoreHeatProcess.WaitForExit();
                }

                IoHelpers.OpenFolderInFileExplorer(binDistDirectory);
            }

            Console.WriteLine();
            Console.WriteLine("FINISHED! Press key to exit...");
            Console.ReadKey();
        }
예제 #23
0
        private static void Main(string[] args)
        {
            // 0. Dump Client version (or else wrong .msi will be created) - Helpers.Constants.ClientVersion
            // 1. Publish with Packager.
            // 2. Build WIX project with Release and x64 configuration.
            // 3. Sign with Packager, set restore true so the password won't be kept.
            var doPublish         = true;
            var doSign            = false;
            var doRestoreThisFile = false;
            var pfxPassword       = "******";

            string pfxPath = "C:\\digicert.pfx";
            string packagerProjectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\"));
            string solutionDirectory        = Path.GetFullPath(Path.Combine(packagerProjectDirectory, "..\\"));
            string guiProjectDirectory      = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.Gui\\"));
            string libraryProjectDirectory  = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi\\"));
            string wixProjectDirectory      = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.WindowsInstaller\\"));
            string binDistDirectory         = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\dist"));

            Console.WriteLine($"{nameof(solutionDirectory)}:\t\t{solutionDirectory}");
            Console.WriteLine($"{nameof(packagerProjectDirectory)}:\t{packagerProjectDirectory}");
            Console.WriteLine($"{nameof(guiProjectDirectory)}:\t\t{guiProjectDirectory}");
            Console.WriteLine($"{nameof(libraryProjectDirectory)}:\t\t{libraryProjectDirectory}");
            Console.WriteLine($"{nameof(wixProjectDirectory)}:\t\t{wixProjectDirectory}");
            Console.WriteLine($"{nameof(binDistDirectory)}:\t\t{binDistDirectory}");

            string versionPrefix  = Helpers.Constants.ClientVersion.ToString();
            string executableName = "wassabee";

            Console.WriteLine();
            Console.WriteLine($"{nameof(versionPrefix)}:\t\t\t{versionPrefix}");
            Console.WriteLine($"{nameof(executableName)}:\t\t\t{executableName}");

            // https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog
            // BOTTLENECKS:
            // Tor - win-32, linux-32, osx-64
            // .NET Core - win-32, linux-64, osx-64
            // Avalonia - win7-32, linux-64, osx-64
            // We'll only support x64, if someone complains, we can come back to it.
            // For 32 bit Windows there needs to be a lot of WIX configuration to be done.
            var targets = new List <string>
            {
                "win7-x64",
                "linux-x64",
                "osx-x64"
            };

            Console.WriteLine();
            Console.Write($"{nameof(targets)}:\t\t\t");
            targets.ForEach(x =>
            {
                if (targets.Last() != x)
                {
                    Console.Write($"{x}, ");
                }
                else
                {
                    Console.Write(x);
                }
            });
            Console.WriteLine();

            if (doPublish)
            {
                if (Directory.Exists(binDistDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(binDistDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {binDistDirectory}");
                }

                var psiBuild = new ProcessStartInfo
                {
                    FileName = "cmd",
                    RedirectStandardInput = true,
                    WorkingDirectory      = guiProjectDirectory
                };
                using (var pBuild = Process.Start(psiBuild))
                {
                    pBuild.StandardInput.WriteLine("dotnet clean --configuration Release && exit");
                    pBuild.WaitForExit();
                }

                var guiBinReleaseDirectory     = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\Release"));
                var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(libraryProjectDirectory, "bin\\Release"));
                if (Directory.Exists(guiBinReleaseDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {guiBinReleaseDirectory}");
                }
                if (Directory.Exists(libraryBinReleaseDirectory))
                {
                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {libraryBinReleaseDirectory}");
                }

                foreach (string target in targets)
                {
                    string currentBinDistDirectory;
                    string publishedFolder = Path.Combine(binDistDirectory, target);
                    string macWasabiAppDir = Path.Combine(publishedFolder, "Wasabi Wallet.App");                     // This should be lowercase .app, but MAC will prevent people from upgrading if we change it.
                    string macContentsDir  = Path.Combine(macWasabiAppDir, "Contents");
                    if (target.StartsWith("osx"))
                    {
                        currentBinDistDirectory = Path.GetFullPath(Path.Combine(macContentsDir, "MacOS"));
                    }
                    else
                    {
                        currentBinDistDirectory = publishedFolder;
                    }
                    Console.WriteLine();
                    Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}");

                    Console.WriteLine();
                    if (!Directory.Exists(currentBinDistDirectory))
                    {
                        Directory.CreateDirectory(currentBinDistDirectory);
                        Console.WriteLine($"Created {currentBinDistDirectory}");
                    }

                    var psiClean = new ProcessStartInfo
                    {
                        FileName         = "dotnet",
                        Arguments        = $"clean",
                        WorkingDirectory = guiProjectDirectory
                    };
                    using (var pClean = Process.Start(psiClean))
                    {
                        pClean.WaitForExit();
                    }

                    // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21
                    // -c|--configuration {Debug|Release}
                    //		Defines the build configuration. The default value is Debug.
                    // --force
                    //		Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file.
                    // -o|--output <OUTPUT_DIRECTORY>
                    //		Specifies the path for the output directory.
                    //		If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or
                    //		./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment.
                    //		If the path is relative, the output directory generated is relative to the project file location, not to the current working directory.
                    // --self-contained
                    //		Publishes the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine.
                    //		If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment.
                    // -r|--runtime <RUNTIME_IDENTIFIER>
                    //		Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD).
                    //		For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD).
                    // --version-suffix <VERSION_SUFFIX>
                    //		Defines the version suffix to replace the asterisk (*) in the version field of the project file.
                    // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x
                    // --disable-parallel
                    //		Disables restoring multiple projects in parallel.
                    // --no-cache
                    //		Specifies to not cache packages and HTTP requests.
                    // https://github.com/dotnet/docs/issues/7568
                    // /p:Version=1.2.3.4
                    //		"dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4
                    var psiPublish = new ProcessStartInfo
                    {
                        FileName         = "dotnet",
                        Arguments        = $"publish --configuration Release --force --output \"{currentBinDistDirectory}\" --self-contained true --runtime \"{target}\" /p:VersionPrefix={versionPrefix} --disable-parallel --no-cache",
                        WorkingDirectory = guiProjectDirectory
                    };
                    using (var pPublish = Process.Start(psiPublish))
                    {
                        pPublish.WaitForExit();
                    }

                    // Remove Tor binaries those are not relevant to the platform.
                    var torFolder   = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "TorDaemons"));
                    var toNotremove = "";
                    if (target.StartsWith("win"))
                    {
                        toNotremove = "win";
                    }
                    else if (target.StartsWith("linux"))
                    {
                        toNotremove = "linux";
                    }
                    else if (target.StartsWith("osx"))
                    {
                        toNotremove = "osx";
                    }
                    foreach (var file in torFolder.EnumerateFiles())
                    {
                        if (!file.Name.Contains("data", StringComparison.OrdinalIgnoreCase) && !file.Name.Contains(toNotremove, StringComparison.OrdinalIgnoreCase))
                        {
                            File.Delete(file.FullName);
                        }
                    }

                    // Rename the final exe.
                    string oldExecutablePath;
                    string newExecutablePath;
                    if (target.StartsWith("win"))
                    {
                        oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe");
                        newExecutablePath = Path.Combine(currentBinDistDirectory, $"{executableName}.exe");
                    }
                    else                     // Linux & OSX
                    {
                        oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui");
                        newExecutablePath = Path.Combine(currentBinDistDirectory, executableName);
                    }
                    File.Move(oldExecutablePath, newExecutablePath);

                    long installedSizeKb = DirSize(new DirectoryInfo(publishedFolder)) / 1000;

                    if (target.StartsWith("win"))
                    {
                        var psiEditbin = new ProcessStartInfo
                        {
                            FileName         = "editbin",
                            Arguments        = $"\"{newExecutablePath}\" /SUBSYSTEM:WINDOWS",
                            WorkingDirectory = currentBinDistDirectory
                        };
                        using (var pEditbin = Process.Start(psiEditbin))
                        {
                            pEditbin.WaitForExit();
                        }

                        var icoPath   = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.ico");
                        var psiRcedit = new ProcessStartInfo
                        {
                            FileName         = "rcedit",
                            Arguments        = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{versionPrefix}\" --set-product-version \"{versionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"",
                            WorkingDirectory = currentBinDistDirectory
                        };
                        using (var pRcedit = Process.Start(psiRcedit))
                        {
                            pRcedit.WaitForExit();
                        }
                    }
                    else if (target.StartsWith("osx"))
                    {
                        string resourcesDir = Path.Combine(macContentsDir, "Resources");
                        string infoFilePath = Path.Combine(macContentsDir, "Info.plist");

                        Directory.CreateDirectory(resourcesDir);
                        var iconpath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.icns");
                        File.Copy(iconpath, Path.Combine(resourcesDir, "WasabiLogo.icns"));

                        string infoContent = $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version = ""1.0"">
<dict>
	<key>LSMinimumSystemVersion</key>
	<string>10.12</string>

	<key>LSArchitecturePriority</key>
	<array>
		<string>x86_64</string>
	</array>

	<key>CFBundleIconFile</key>
	<string>WasabiLogo.icns</string>

	<key>CFBundlePackageType</key>
	<string>APPL</string>

	<key>CFBundleShortVersionString</key>
	<string>{versionPrefix}</string>

	<key>CFBundleVersion</key>
	<string>{versionPrefix}</string>

	<key>CFBundleExecutable</key>
	<string>{executableName}</string>

	<key>CFBundleName</key>
	<string>Wasabi Wallet</string>

	<key>CFBundleIdentifier</key>
	<string>zksnacks.wasabiwallet</string>

	<key>NSHighResolutionCapable</key>
	<true/>

	<key>NSAppleScriptEnabled</key>
	<true/>

	<key>LSApplicationCategoryType</key>
	<string>public.app-category.finance</string>

	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
</dict>
</plist>
";
                        File.WriteAllText(infoFilePath, infoContent);

                        var psiCreateSymLink = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = publishedFolder
                        };
                        using (var createSymLinkProcess = Process.Start(psiCreateSymLink))
                        {
                            createSymLinkProcess.StandardInput.WriteLine($"wsl ln -s /Applications && exit");
                            createSymLinkProcess.WaitForExit();
                        }

                        //how to generate .DS_Store file - https://github.com/zkSNACKs/WalletWasabi/pull/928/commits/e38ed672dee25f6e45a3eb16584887cc6d48c4e6
                        var dmgContentDir = Path.Combine(packagerProjectDirectory, "Content", "Osx");
                        IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentDir), new DirectoryInfo(publishedFolder));

                        var psiGenIsoImage = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };

                        string uncompressedDmgFileName = $"Wasabi-uncompressed.dmg";
                        string uncompressedDmgFilePath = Path.Combine(binDistDirectory, uncompressedDmgFileName);
                        string dmgFileName             = $"Wasabi-{versionPrefix}.dmg";
                        using (var genIsoImageProcess = Process.Start(psiGenIsoImage))
                        {
                            // http://www.nathancoulson.com/proj_cross_tools.php
                            // -D: Do not use deep directory relocation, and instead just pack them in the way we see them
                            // -V: Volume Label
                            // -no-pad: Do not pad the end by 150 sectors (300kb). As it is not a cd image, not required
                            // -apple -r: Creates a .dmg image
                            genIsoImageProcess.StandardInput.WriteLine($"wsl genisoimage -D -V \"Wasabi Wallet\" -no-pad -apple -r -dir-mode 755 -o \"{uncompressedDmgFileName}\" \"{new DirectoryInfo(publishedFolder).Name}\" && exit");
                            genIsoImageProcess.WaitForExit();
                        }
                        // cd ~
                        // git clone https://github.com/planetbeing/libdmg-hfsplus.git && cd libdmg-hfsplus
                        // https://github.com/planetbeing/libdmg-hfsplus/issues/14
                        // mkdir build && cd build
                        // sudo apt-get install zlib1g-dev
                        // cmake ..
                        // cd build
                        // sudo apt-get install libssl1.0-dev
                        // cmake ..
                        // cd ~/libdmg-hfsplus/build/
                        // make
                        var psiDmg = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        using (var dmgProcess = Process.Start(psiDmg))
                        {
                            dmgProcess.StandardInput.WriteLine($"wsl ~/libdmg-hfsplus/build/dmg/./dmg dmg \"{uncompressedDmgFileName}\" \"{dmgFileName}\" && exit");
                            dmgProcess.WaitForExit();
                        }
                        // In case compression above doesn't work:
                        //var psiBzip = new ProcessStartInfo
                        //{
                        //	FileName = "cmd",
                        //	RedirectStandardInput = true,
                        //	WorkingDirectory = binDistDirectory
                        //};
                        //var bzipProcess = Process.Start(psiBzip);
                        //bzipProcess.StandardInput.WriteLine($"wsl bzip2 \"{uncompressedDmgFileName}\" && exit");
                        //bzipProcess.WaitForExit();

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        File.Delete(uncompressedDmgFilePath);

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                    else if (target.StartsWith("linux"))
                    {
                        Console.WriteLine("Create Linux .tar.gz");
                        if (!Directory.Exists(publishedFolder))
                        {
                            throw new Exception($"{publishedFolder} doesn't exist.");
                        }
                        var newFolderName = $"WasabiLinux-{versionPrefix}";
                        var newFolderPath = Path.Combine(binDistDirectory, newFolderName);
                        Directory.Move(publishedFolder, newFolderPath);
                        publishedFolder = newFolderPath;

                        var psiTar = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        using (var tarProcess = Process.Start(psiTar))
                        {
                            tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit");
                            tarProcess.WaitForExit();
                        }

                        Console.WriteLine("Create Linux .deb");

                        var debFolderRelativePath            = "deb";
                        var debFolderPath                    = Path.Combine(binDistDirectory, debFolderRelativePath);
                        var linuxUsrLocalBinFolder           = "/usr/local/bin/";
                        var debUsrLocalBinFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "local", "bin");
                        var debUsrLocalBinFolderPath         = Path.Combine(binDistDirectory, debUsrLocalBinFolderRelativePath);
                        Directory.CreateDirectory(debUsrLocalBinFolderPath);
                        var debUsrAppFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "share", "applications");
                        var debUsrAppFolderPath         = Path.Combine(binDistDirectory, debUsrAppFolderRelativePath);
                        Directory.CreateDirectory(debUsrAppFolderPath);
                        var debUsrShareIconsFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "share", "icons", "hicolor");
                        var debUsrShareIconsFolderPath         = Path.Combine(binDistDirectory, debUsrShareIconsFolderRelativePath);
                        var debianFolderRelativePath           = Path.Combine(debFolderRelativePath, "DEBIAN");
                        var debianFolderPath = Path.Combine(binDistDirectory, debianFolderRelativePath);
                        Directory.CreateDirectory(debianFolderPath);
                        newFolderName = "wasabiwallet";
                        var linuxWasabiWalletFolder = LinuxPathCombine(linuxUsrLocalBinFolder, newFolderName);
                        var newFolderRelativePath   = Path.Combine(debUsrLocalBinFolderRelativePath, newFolderName);
                        newFolderPath = Path.Combine(binDistDirectory, newFolderRelativePath);
                        Directory.Move(publishedFolder, newFolderPath);

                        var assetsFolder = Path.Combine(guiProjectDirectory, "Assets");
                        var assetsInfo   = new DirectoryInfo(assetsFolder);

                        foreach (var file in assetsInfo.EnumerateFiles())
                        {
                            var number = file.Name.Split(new string[] { "WasabiLogo", ".png" }, StringSplitOptions.RemoveEmptyEntries);
                            if (number.Count() == 1 && int.TryParse(number.First(), out int size))
                            {
                                string destFolder = Path.Combine(debUsrShareIconsFolderPath, $"{size}x{size}", "apps");
                                Directory.CreateDirectory(destFolder);
                                file.CopyTo(Path.Combine(destFolder, $"{executableName}.png"));
                            }
                        }

                        var controlFilePath = Path.Combine(debianFolderPath, "control");
                        // License format doesn't yet work, but should work in the future, it's work in progress: https://bugs.launchpad.net/ubuntu/+source/software-center/+bug/435183
                        var controlFileContent = $"Package: {executableName}\n" +
                                                 $"Priority: optional\n" +
                                                 $"Section: utils\n" +
                                                 $"Maintainer: nopara73 <*****@*****.**>\n" +
                                                 $"Version: {versionPrefix}\n" +
                                                 $"Homepage: http://wasabiwallet.io\n" +
                                                 $"Vcs-Git: git://github.com/zkSNACKs/WalletWasabi.git\n" +
                                                 $"Vcs-Browser: https://github.com/zkSNACKs/WalletWasabi\n" +
                                                 $"Architecture: amd64\n" +
                                                 $"License: Open Source (MIT)\n" +
                                                 $"Installed-Size: {installedSizeKb}\n" +
                                                 $"Description: open-source, non-custodial, privacy focused Bitcoin wallet\n" +
                                                 $"  Built-in Tor, CoinJoin and Coin Control features.\n";

                        File.WriteAllText(controlFilePath, controlFileContent, Encoding.ASCII);

                        var desktopFilePath    = Path.Combine(debUsrAppFolderPath, $"{executableName}.desktop");
                        var desktopFileContent = $"[Desktop Entry]\n" +
                                                 $"Type=Application\n" +
                                                 $"Name=Wasabi Wallet\n" +
                                                 $"GenericName=Bitcoin Wallet\n" +
                                                 $"Comment=Privacy focused Bitcoin wallet.\n" +
                                                 $"Icon={executableName}\n" +
                                                 $"Terminal=false\n" +
                                                 $"Exec={executableName}\n" +
                                                 $"Categories=Office;Finance;\n" +
                                                 $"Keywords=bitcoin;wallet;crypto;blockchain;wasabi;privacy;anon;awesome;qwe;asd;\n";

                        File.WriteAllText(desktopFilePath, desktopFileContent, Encoding.ASCII);

                        var wasabiStarterScriptPath    = Path.Combine(debUsrLocalBinFolderPath, $"{executableName}");
                        var wasabiStarterScriptContent = $"#!/bin/sh\n" +
                                                         $"{ linuxWasabiWalletFolder.TrimEnd('/')}/./{executableName}\n";

                        File.WriteAllText(wasabiStarterScriptPath, wasabiStarterScriptContent, Encoding.ASCII);

                        string debExeLinuxPath              = LinuxPathCombine(newFolderRelativePath, executableName);
                        string debDestopFileLinuxPath       = LinuxPathCombine(debUsrAppFolderRelativePath, $"{executableName}.desktop");
                        var    wasabiStarterScriptLinuxPath = LinuxPathCombine(debUsrLocalBinFolderRelativePath, $"{executableName}");
                        var    psi = new ProcessStartInfo
                        {
                            FileName              = "wsl",
                            Arguments             = $"cd ~ && sudo umount /mnt/c && sudo mount -t drvfs C: /mnt/c -o metadata && cd /mnt/c/Users/user/Desktop/WalletWasabi/WalletWasabi.Gui/bin/dist && sudo chmod +x {debExeLinuxPath} && sudo chmod +x {wasabiStarterScriptLinuxPath} && sudo chmod -R 0644 {debDestopFileLinuxPath} && sudo chmod -R 0775 {LinuxPath(debianFolderRelativePath)} && dpkg --build {LinuxPath(debFolderRelativePath)} $(pwd)",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };

                        using (var p = Process.Start(psi))
                        {
                            p.WaitForExit();
                        }

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(debFolderPath).GetAwaiter().GetResult();

                        string oldDeb = Path.Combine(binDistDirectory, $"{executableName}_{versionPrefix}_amd64.deb");
                        string newDeb = Path.Combine(binDistDirectory, $"Wasabi-{versionPrefix}.deb");
                        File.Move(oldDeb, newDeb);

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                }
            }

            if (doSign is true)
            {
                foreach (string target in targets)
                {
                    if (target.StartsWith("win", StringComparison.OrdinalIgnoreCase))
                    {
                        string publishedFolder = Path.Combine(binDistDirectory, target);

                        Console.WriteLine("Move created .msi");
                        var msiPath = Path.Combine(wixProjectDirectory, @"bin\Release\Wasabi.msi");
                        if (!File.Exists(msiPath))
                        {
                            throw new Exception(".msi doesn't exist. Expected path: Wasabi.msi.");
                        }
                        var msiFileName = Path.GetFileNameWithoutExtension(msiPath);
                        var newMsiPath  = Path.Combine(binDistDirectory, $"{msiFileName}-{versionPrefix}.msi");
                        File.Move(msiPath, newMsiPath);

                        // Sign code with digicert.
                        var psiSigntool = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = binDistDirectory
                        };
                        using (var signToolProcess = Process.Start(psiSigntool))
                        {
                            signToolProcess.StandardInput.WriteLine($"signtool sign /d \"Wasabi Wallet\" /f \"{pfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit");
                            signToolProcess.WaitForExit();
                        }

                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                        Console.WriteLine($"Deleted {publishedFolder}");
                    }
                }

                Console.WriteLine("Signing final files...");
                var finalFiles = Directory.GetFiles(binDistDirectory);

                foreach (var finalFile in finalFiles)
                {
                    var psiSignProcess = new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory      = binDistDirectory
                    };
                    using (var signProcess = Process.Start(psiSignProcess))
                    {
                        signProcess.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit");
                        signProcess.WaitForExit();
                    }

                    var psiRestoreHeat = new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory      = wixProjectDirectory
                    };
                    using (var restoreHeatProcess = Process.Start(psiRestoreHeat))
                    {
                        restoreHeatProcess.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit");
                        restoreHeatProcess.WaitForExit();
                    }

                    if (doRestoreThisFile)
                    {
                        var psiRestoreThisFile = new ProcessStartInfo
                        {
                            FileName = "cmd",
                            RedirectStandardInput = true,
                            WorkingDirectory      = packagerProjectDirectory
                        };
                        using (var restoreThisFileProcess = Process.Start(psiRestoreThisFile))
                        {
                            restoreThisFileProcess.StandardInput.WriteLine($"git checkout -- Program.cs && exit");
                            restoreThisFileProcess.WaitForExit();
                        }
                    }
                }

                IoHelpers.OpenFolderInFileExplorer(binDistDirectory);
                return;                 // No need for readkey here.
            }
        }
예제 #24
0
        private static void Sign()
        {
            foreach (string target in Targets)
            {
                if (target.StartsWith("win", StringComparison.OrdinalIgnoreCase))
                {
                    string publishedFolder = Path.Combine(BinDistDirectory, target);

                    Console.WriteLine("Move created .msi");
                    var msiPath = Path.Combine(WixProjectDirectory, @"bin\Release\Wasabi.msi");
                    if (!File.Exists(msiPath))
                    {
                        throw new Exception(".msi does not exist. Expected path: Wasabi.msi.");
                    }
                    var msiFileName = Path.GetFileNameWithoutExtension(msiPath);
                    var newMsiPath  = Path.Combine(BinDistDirectory, $"{msiFileName}-{VersionPrefix}.msi");
                    File.Move(msiPath, newMsiPath);

                    Console.Write("Enter Code Signing Certificate Password: "******"cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory = BinDistDirectory
                    }))
                    {
                        process.StandardInput.WriteLine($"signtool sign /d \"Wasabi Wallet\" /f \"{PfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit");
                        process.WaitForExit();
                    }

                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {publishedFolder}");
                }
            }

            Console.WriteLine("Signing final files...");
            var finalFiles = Directory.GetFiles(BinDistDirectory);

            foreach (var finalFile in finalFiles)
            {
                using (var process = Process.Start(new ProcessStartInfo
                {
                    FileName = "cmd",
                    RedirectStandardInput = true,
                    WorkingDirectory = BinDistDirectory
                }))
                {
                    process.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit");
                    process.WaitForExit();
                }

                using (var process = Process.Start(new ProcessStartInfo
                {
                    FileName = "cmd",
                    RedirectStandardInput = true,
                    WorkingDirectory = WixProjectDirectory
                }))
                {
                    process.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit");
                    process.WaitForExit();
                }
            }

            IoHelpers.OpenFolderInFileExplorer(BinDistDirectory);
        }
예제 #25
0
        public static async Task <CoreNode> CreateAsync(CoreNodeParams coreNodeParams, CancellationToken cancel)
        {
            Guard.NotNull(nameof(coreNodeParams), coreNodeParams);
            using (BenchmarkLogger.Measure())
            {
                var coreNode = new CoreNode();
                coreNode.DataDir        = coreNodeParams.DataDir;
                coreNode.Network        = coreNodeParams.Network;
                coreNode.MempoolService = coreNodeParams.MempoolService;

                var configPath = Path.Combine(coreNode.DataDir, "bitcoin.conf");
                coreNode.Config = new CoreConfig();
                if (File.Exists(configPath))
                {
                    var configString = await File.ReadAllTextAsync(configPath).ConfigureAwait(false);

                    coreNode.Config.TryAdd(configString);
                }

                var      configDic         = coreNode.Config.ToDictionary();
                string   rpcUser           = null;
                string   rpcPassword       = null;
                EndPoint whitebind         = null;
                string   rpcHost           = null;
                int?     rpcPort           = null;
                string   rpcCookieFilePath = null;
                foreach (var networkPrefixWithDot in NetworkTranslator.GetConfigPrefixesWithDots(coreNode.Network))
                {
                    var rpcc = configDic.TryGet($"{networkPrefixWithDot}rpccookiefile");
                    var ru   = configDic.TryGet($"{networkPrefixWithDot}rpcuser");
                    var rp   = configDic.TryGet($"{networkPrefixWithDot}rpcpassword");
                    var wbs  = configDic.TryGet($"{networkPrefixWithDot}whitebind");
                    var rpst = configDic.TryGet($"{networkPrefixWithDot}rpchost");
                    var rpts = configDic.TryGet($"{networkPrefixWithDot}rpcport");

                    if (rpcc != null)
                    {
                        rpcCookieFilePath = rpcc;
                    }
                    if (ru != null)
                    {
                        rpcUser = ru;
                    }
                    if (rp != null)
                    {
                        rpcPassword = rp;
                    }
                    if (wbs != null && EndPointParser.TryParse(wbs, coreNode.Network.DefaultPort, out EndPoint wb))
                    {
                        whitebind = wb;
                    }
                    if (rpst != null)
                    {
                        rpcHost = rpst;
                    }
                    if (rpts != null && int.TryParse(rpts, out int rpt))
                    {
                        rpcPort = rpt;
                    }
                }

                string authString;
                bool   cookieAuth = rpcCookieFilePath != null;
                if (cookieAuth)
                {
                    authString = $"cookiefile={rpcCookieFilePath}";
                }
                else
                {
                    rpcUser ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    rpcPassword ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    authString = $"{rpcUser}:{rpcPassword}";
                }

                coreNode.P2pEndPoint = whitebind ?? coreNodeParams.P2pEndPointStrategy.EndPoint;
                rpcHost ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetHostOrDefault();
                rpcPort ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetPortOrDefault();
                EndPointParser.TryParse($"{rpcHost}:{rpcPort}", coreNode.Network.RPCPort, out EndPoint rpce);
                coreNode.RpcEndPoint = rpce;

                coreNode.RpcClient = new RPCClient($"{authString}", coreNode.RpcEndPoint.ToString(coreNode.Network.DefaultPort), coreNode.Network);

                if (coreNodeParams.TryRestart)
                {
                    await coreNode.TryStopAsync(false).ConfigureAwait(false);
                }

                if (coreNodeParams.TryDeleteDataDir)
                {
                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(coreNode.DataDir).ConfigureAwait(false);
                }

                IoHelpers.EnsureDirectoryExists(coreNode.DataDir);

                var configPrefix       = NetworkTranslator.GetConfigPrefix(coreNode.Network);
                var desiredConfigLines = new List <string>()
                {
                    $"{configPrefix}.server			= 1",
                    $"{configPrefix}.listen			= 1",
                    $"{configPrefix}.whitebind		= {coreNode.P2pEndPoint.ToString(coreNode.Network.DefaultPort)}",
                    $"{configPrefix}.rpchost		= {coreNode.RpcEndPoint.GetHostOrDefault()}",
                    $"{configPrefix}.rpcport		= {coreNode.RpcEndPoint.GetPortOrDefault()}"
                };

                if (!cookieAuth)
                {
                    desiredConfigLines.Add($"{configPrefix}.rpcuser		= {coreNode.RpcClient.CredentialString.UserPassword.UserName}");
                    desiredConfigLines.Add($"{configPrefix}.rpcpassword	= {coreNode.RpcClient.CredentialString.UserPassword.Password}");
                }

                if (coreNodeParams.TxIndex != null)
                {
                    desiredConfigLines.Add($"{configPrefix}.txindex = {coreNodeParams.TxIndex}");
                }

                if (coreNodeParams.Prune != null)
                {
                    desiredConfigLines.Add($"{configPrefix}.prune = {coreNodeParams.Prune}");
                }

                var sectionComment = $"# The following configuration options were added or modified by Wasabi Wallet.";
                // If the comment is not already present.
                // And there would be new config entries added.
                var throwAwayConfig = new CoreConfig(coreNode.Config);
                throwAwayConfig.AddOrUpdate(string.Join(Environment.NewLine, desiredConfigLines));
                if (!coreNode.Config.ToString().Contains(sectionComment, StringComparison.Ordinal) &&
                    throwAwayConfig.Count != coreNode.Config.Count)
                {
                    desiredConfigLines.Insert(0, sectionComment);
                }

                if (coreNode.Config.AddOrUpdate(string.Join(Environment.NewLine, desiredConfigLines)) ||
                    !File.Exists(configPath))
                {
                    IoHelpers.EnsureContainingDirectoryExists(configPath);
                    await File.WriteAllTextAsync(configPath, coreNode.Config.ToString());
                }

                // If it isn't already running, then we run it.
                if (await coreNode.RpcClient.TestAsync().ConfigureAwait(false) is null)
                {
                    Logger.LogInfo("Bitcoin Core is already running.");
                }
예제 #26
0
        private static void Publish()
        {
            if (Directory.Exists(BinDistDirectory))
            {
                IoHelpers.DeleteRecursivelyWithMagicDustAsync(BinDistDirectory).GetAwaiter().GetResult();
                Console.WriteLine($"Deleted {BinDistDirectory}");
            }

            using (var process = Process.Start(new ProcessStartInfo
            {
                FileName = "cmd",
                RedirectStandardInput = true,
                WorkingDirectory = GuiProjectDirectory
            }))
            {
                process.StandardInput.WriteLine("dotnet clean --configuration Release && exit");
                process.WaitForExit();
            }

            var guiBinReleaseDirectory     = Path.GetFullPath(Path.Combine(GuiProjectDirectory, "bin\\Release"));
            var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(LibraryProjectDirectory, "bin\\Release"));

            if (Directory.Exists(guiBinReleaseDirectory))
            {
                IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult();
                Console.WriteLine($"Deleted {guiBinReleaseDirectory}");
            }
            if (Directory.Exists(libraryBinReleaseDirectory))
            {
                IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult();
                Console.WriteLine($"Deleted {libraryBinReleaseDirectory}");
            }

            foreach (string target in Targets)
            {
                string publishedFolder         = Path.Combine(BinDistDirectory, target);
                string currentBinDistDirectory = publishedFolder;

                Console.WriteLine();
                Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}");

                Console.WriteLine();
                if (!Directory.Exists(currentBinDistDirectory))
                {
                    Directory.CreateDirectory(currentBinDistDirectory);
                    Console.WriteLine($"Created {currentBinDistDirectory}");
                }

                using (var process = Process.Start(new ProcessStartInfo
                {
                    FileName = "dotnet",
                    Arguments = $"clean",
                    WorkingDirectory = GuiProjectDirectory
                }))
                {
                    process.WaitForExit();
                }

                // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21
                // -c|--configuration {Debug|Release}
                //		Defines the build configuration. The default value is Debug.
                // --force
                //		Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file.
                // -o|--output <OUTPUT_DIRECTORY>
                //		Specifies the path for the output directory.
                //		If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or
                //		./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment.
                //		If the path is relative, the output directory generated is relative to the project file location, not to the current working directory.
                // --self-contained
                //		Publishes the .NET Core runtime with your application so the runtime does not need to be installed on the target machine.
                //		If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment.
                // -r|--runtime <RUNTIME_IDENTIFIER>
                //		Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD).
                //		For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD).
                // --version-suffix <VERSION_SUFFIX>
                //		Defines the version suffix to replace the asterisk (*) in the version field of the project file.
                // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x
                // --disable-parallel
                //		Disables restoring multiple projects in parallel.
                // --no-cache
                //		Specifies to not cache packages and HTTP requests.
                // https://github.com/dotnet/docs/issues/7568
                // /p:Version=1.2.3.4
                //		"dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4
                using (var process = Process.Start(new ProcessStartInfo
                {
                    FileName = "dotnet",
                    Arguments = $"publish --configuration Release --force --output \"{currentBinDistDirectory}\" --self-contained true --runtime \"{target}\" /p:VersionPrefix={VersionPrefix} --disable-parallel --no-cache /p:DebugType=none /p:DebugSymbols=false /p:ErrorReport=none /p:DocumentationFile=\"\" /p:Deterministic=true",
                    WorkingDirectory = GuiProjectDirectory
                }))
                {
                    process.WaitForExit();
                }

                Tools.ClearSha512Tags(currentBinDistDirectory);
                //Tools.RemoveSosDocsUnix(currentBinDistDirectory);

                // Remove Tor binaries that are not relevant to the platform.
                var torFolder   = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "TorDaemons"));
                var toNotRemove = "";
                if (target.StartsWith("win"))
                {
                    toNotRemove = "win";
                }
                else if (target.StartsWith("linux"))
                {
                    toNotRemove = "lin";
                }
                else if (target.StartsWith("osx"))
                {
                    toNotRemove = "osx";
                }

                foreach (var file in torFolder.EnumerateFiles())
                {
                    if (!file.Name.Contains("data", StringComparison.OrdinalIgnoreCase) && !file.Name.Contains(toNotRemove, StringComparison.OrdinalIgnoreCase))
                    {
                        File.Delete(file.FullName);
                    }
                }

                // Remove binaries that are not relevant to the platform.
                var binaryFolder = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "Microservices", "Binaries"));

                foreach (var dir in binaryFolder.EnumerateDirectories())
                {
                    if (!dir.Name.Contains(toNotRemove, StringComparison.OrdinalIgnoreCase))
                    {
                        IoHelpers.DeleteRecursivelyWithMagicDustAsync(dir.FullName).GetAwaiter().GetResult();
                    }
                }

                // Rename the final exe.
                string oldExecutablePath;
                string newExecutablePath;
                if (target.StartsWith("win"))
                {
                    oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe");
                    newExecutablePath = Path.Combine(currentBinDistDirectory, $"{ExecutableName}.exe");
                }
                else                 // Linux & OSX
                {
                    oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui");
                    newExecutablePath = Path.Combine(currentBinDistDirectory, ExecutableName);
                }
                File.Move(oldExecutablePath, newExecutablePath);

                long installedSizeKb = Tools.DirSize(new DirectoryInfo(publishedFolder)) / 1000;

                if (target.StartsWith("win"))
                {
                    var icoPath = Path.Combine(GuiProjectDirectory, "Assets", "WasabiLogo.ico");
                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "rcedit",                         // https://github.com/electron/rcedit/
                        Arguments = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{VersionPrefix}\" --set-product-version \"{VersionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"",
                        WorkingDirectory = currentBinDistDirectory
                    }))
                    {
                        process.WaitForExit();
                    }

                    var daemonExePath = newExecutablePath.Substring(0, newExecutablePath.Length - 4) + "d.exe";
                    File.Copy(newExecutablePath, daemonExePath);

                    // Do not open console.
                    if (!NSubsysUtil.ProcessFile(newExecutablePath))
                    {
                        Console.WriteLine("ERROR: Could not remove console from exe.");
                    }

                    // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!!
                    if (OnlyBinaries)
                    {
                        continue;                         // In Windows build at this moment it does not matter though.
                    }
                }
                else if (target.StartsWith("osx"))
                {
                    // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!!
                    if (OnlyBinaries)
                    {
                        continue;
                    }

                    var tempName = Path.Combine(BinDistDirectory, $"temp-{target}");
                    Directory.Move(currentBinDistDirectory, tempName);
                    currentBinDistDirectory = tempName;

                    string macWasabiAppDir = Path.Combine(publishedFolder, "Wasabi Wallet.App");                     // This should be lowercase .app, but MAC will prevent people from upgrading if we change it.
                    string macContentsDir  = Path.Combine(macWasabiAppDir, "Contents");
                    string newName         = Path.GetFullPath(Path.Combine(macContentsDir, "MacOS"));
                    Directory.CreateDirectory(macContentsDir);
                    Directory.Move(currentBinDistDirectory, newName);
                    currentBinDistDirectory = newName;

                    string resourcesDir = Path.Combine(macContentsDir, "Resources");
                    string infoFilePath = Path.Combine(macContentsDir, "Info.plist");

                    Directory.CreateDirectory(resourcesDir);
                    var iconPath = Path.Combine(GuiProjectDirectory, "Assets", "WasabiLogo.icns");
                    File.Copy(iconPath, Path.Combine(resourcesDir, "WasabiLogo.icns"));

                    string infoContent = $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version = ""1.0"">
<dict>
	<key>LSMinimumSystemVersion</key>
	<string>10.12</string>

	<key>LSArchitecturePriority</key>
	<array>
		<string>x86_64</string>
	</array>

	<key>CFBundleIconFile</key>
	<string>WasabiLogo.icns</string>

	<key>CFBundlePackageType</key>
	<string>APPL</string>

	<key>CFBundleShortVersionString</key>
	<string>{VersionPrefix}</string>

	<key>CFBundleVersion</key>
	<string>{VersionPrefix}</string>

	<key>CFBundleExecutable</key>
	<string>{ExecutableName}</string>

	<key>CFBundleName</key>
	<string>Wasabi Wallet</string>

	<key>CFBundleIdentifier</key>
	<string>zksnacks.wasabiwallet</string>

	<key>NSHighResolutionCapable</key>
	<true/>

	<key>NSAppleScriptEnabled</key>
	<true/>

	<key>LSApplicationCategoryType</key>
	<string>public.app-category.finance</string>

	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
</dict>
</plist>
";
                    File.WriteAllText(infoFilePath, infoContent);

                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory = publishedFolder
                    }))
                    {
                        process.StandardInput.WriteLine($"wsl ln -s /Applications && exit");
                        process.WaitForExit();
                    }

                    //how to generate .DS_Store file - https://github.com/zkSNACKs/WalletWasabi/pull/928/commits/e38ed672dee25f6e45a3eb16584887cc6d48c4e6
                    var dmgContentDir = Path.Combine(PackagerProjectDirectory, "Content", "Osx");
                    IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentDir), new DirectoryInfo(publishedFolder));

                    string uncompressedDmgFileName = $"Wasabi-uncompressed.dmg";
                    string uncompressedDmgFilePath = Path.Combine(BinDistDirectory, uncompressedDmgFileName);
                    string dmgFileName             = $"Wasabi-{VersionPrefix}.dmg";
                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory = BinDistDirectory
                    }))
                    {
                        // http://www.nathancoulson.com/proj_cross_tools.php
                        // -D: Do not use deep directory relocation, and instead just pack them in the way we see them
                        // -V: Volume Label
                        // -no-pad: Do not pad the end by 150 sectors (300kb). As it is not a cd image, not required
                        // -apple -r: Creates a .dmg image
                        process.StandardInput.WriteLine($"wsl genisoimage -D -V \"Wasabi Wallet\" -no-pad -apple -r -dir-mode 755 -o \"{uncompressedDmgFileName}\" \"{new DirectoryInfo(publishedFolder).Name}\" && exit");
                        process.WaitForExit();
                    }
                    // cd ~
                    // git clone https://github.com/planetbeing/libdmg-hfsplus.git && cd libdmg-hfsplus
                    // https://github.com/planetbeing/libdmg-hfsplus/issues/14
                    // mkdir build && cd build
                    // sudo apt-get install zlib1g-dev
                    // cmake ..
                    // cd build
                    // sudo apt-get install libssl1.0-dev
                    // cmake ..
                    // cd ~/libdmg-hfsplus/build/
                    // make
                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "cmd",
                        RedirectStandardInput = true,
                        WorkingDirectory = BinDistDirectory
                    }))
                    {
                        process.StandardInput.WriteLine($"wsl ~/libdmg-hfsplus/build/dmg/./dmg dmg \"{uncompressedDmgFileName}\" \"{dmgFileName}\" && exit");
                        process.WaitForExit();
                    }

                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                    File.Delete(uncompressedDmgFilePath);

                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {publishedFolder}");
                }
                else if (target.StartsWith("linux"))
                {
                    // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!!
                    if (OnlyBinaries)
                    {
                        continue;
                    }

                    Console.WriteLine("Create Linux .tar.gz");
                    if (!Directory.Exists(publishedFolder))
                    {
                        throw new Exception($"{publishedFolder} does not exist.");
                    }
                    var newFolderName = $"WasabiLinux-{VersionPrefix}";
                    var newFolderPath = Path.Combine(BinDistDirectory, newFolderName);
                    Directory.Move(publishedFolder, newFolderPath);
                    publishedFolder = newFolderPath;

                    var linuxPath = $"/mnt/c/{Tools.LinuxPath(BinDistDirectory.Replace("C:\\", ""))}";                     // We assume that it is on drive C:\.

                    var commands = new[]
                    {
                        "cd ~",
                        "sudo umount /mnt/c",
                        "sudo mount -t drvfs C: /mnt/c -o metadata",
                        $"cd {linuxPath}",
                        $"sudo find ./{newFolderName} -type f -exec chmod 644 {{}} \\;",
                        $"sudo find ./{newFolderName} -type f \\( -name 'wassabee' -o -name 'hwi' -o -name 'bitcoind' \\) -exec chmod +x {{}} \\;",
                        $"tar -pczvf {newFolderName}.tar.gz {newFolderName}"
                    };
                    string arguments = string.Join(" && ", commands);

                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "wsl",
                        Arguments = arguments,
                        RedirectStandardInput = true,
                        WorkingDirectory = BinDistDirectory
                    }))
                    {
                        process.WaitForExit();
                    }

                    Console.WriteLine("Create Linux .deb");

                    var debFolderRelativePath            = "deb";
                    var debFolderPath                    = Path.Combine(BinDistDirectory, debFolderRelativePath);
                    var linuxUsrLocalBinFolder           = "/usr/local/bin/";
                    var debUsrLocalBinFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "local", "bin");
                    var debUsrLocalBinFolderPath         = Path.Combine(BinDistDirectory, debUsrLocalBinFolderRelativePath);
                    Directory.CreateDirectory(debUsrLocalBinFolderPath);
                    var debUsrAppFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "share", "applications");
                    var debUsrAppFolderPath         = Path.Combine(BinDistDirectory, debUsrAppFolderRelativePath);
                    Directory.CreateDirectory(debUsrAppFolderPath);
                    var debUsrShareIconsFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "share", "icons", "hicolor");
                    var debUsrShareIconsFolderPath         = Path.Combine(BinDistDirectory, debUsrShareIconsFolderRelativePath);
                    var debianFolderRelativePath           = Path.Combine(debFolderRelativePath, "DEBIAN");
                    var debianFolderPath = Path.Combine(BinDistDirectory, debianFolderRelativePath);
                    Directory.CreateDirectory(debianFolderPath);
                    newFolderName = "wasabiwallet";
                    var linuxWasabiWalletFolder = Tools.LinuxPathCombine(linuxUsrLocalBinFolder, newFolderName);
                    var newFolderRelativePath   = Path.Combine(debUsrLocalBinFolderRelativePath, newFolderName);
                    newFolderPath = Path.Combine(BinDistDirectory, newFolderRelativePath);
                    Directory.Move(publishedFolder, newFolderPath);

                    var assetsFolder = Path.Combine(GuiProjectDirectory, "Assets");
                    var assetsInfo   = new DirectoryInfo(assetsFolder);

                    foreach (var file in assetsInfo.EnumerateFiles())
                    {
                        var number = file.Name.Split(new string[] { "WasabiLogo", ".png" }, StringSplitOptions.RemoveEmptyEntries);
                        if (number.Length == 1 && int.TryParse(number.First(), out int size))
                        {
                            string destFolder = Path.Combine(debUsrShareIconsFolderPath, $"{size}x{size}", "apps");
                            Directory.CreateDirectory(destFolder);
                            file.CopyTo(Path.Combine(destFolder, $"{ExecutableName}.png"));
                        }
                    }

                    var controlFilePath = Path.Combine(debianFolderPath, "control");
                    // License format does not yet work, but should work in the future, it's work in progress: https://bugs.launchpad.net/ubuntu/+source/software-center/+bug/435183
                    var controlFileContent = $"Package: {ExecutableName}\n" +
                                             $"Priority: optional\n" +
                                             $"Section: utils\n" +
                                             $"Maintainer: nopara73 <*****@*****.**>\n" +
                                             $"Version: {VersionPrefix}\n" +
                                             $"Homepage: http://wasabiwallet.io\n" +
                                             $"Vcs-Git: git://github.com/zkSNACKs/WalletWasabi.git\n" +
                                             $"Vcs-Browser: https://github.com/zkSNACKs/WalletWasabi\n" +
                                             $"Architecture: amd64\n" +
                                             $"License: Open Source (MIT)\n" +
                                             $"Installed-Size: {installedSizeKb}\n" +
                                             $"Description: open-source, non-custodial, privacy focused Bitcoin wallet\n" +
                                             $"  Built-in Tor, CoinJoin and Coin Control features.\n";

                    File.WriteAllText(controlFilePath, controlFileContent, Encoding.ASCII);

                    var desktopFilePath    = Path.Combine(debUsrAppFolderPath, $"{ExecutableName}.desktop");
                    var desktopFileContent = $"[Desktop Entry]\n" +
                                             $"Type=Application\n" +
                                             $"Name=Wasabi Wallet\n" +
                                             $"StartupWMClass=Wasabi Wallet\n" +
                                             $"GenericName=Bitcoin Wallet\n" +
                                             $"Comment=Privacy focused Bitcoin wallet.\n" +
                                             $"Icon={ExecutableName}\n" +
                                             $"Terminal=false\n" +
                                             $"Exec={ExecutableName}\n" +
                                             $"Categories=Office;Finance;\n" +
                                             $"Keywords=bitcoin;wallet;crypto;blockchain;wasabi;privacy;anon;awesome;qwe;asd;\n";

                    File.WriteAllText(desktopFilePath, desktopFileContent, Encoding.ASCII);

                    var wasabiStarterScriptPath    = Path.Combine(debUsrLocalBinFolderPath, $"{ExecutableName}");
                    var wasabiStarterScriptContent = $"#!/bin/sh\n" +
                                                     $"{ linuxWasabiWalletFolder.TrimEnd('/')}/{ExecutableName} $@\n";

                    File.WriteAllText(wasabiStarterScriptPath, wasabiStarterScriptContent, Encoding.ASCII);

                    string debExeLinuxPath        = Tools.LinuxPathCombine(newFolderRelativePath, ExecutableName);
                    string debDestopFileLinuxPath = Tools.LinuxPathCombine(debUsrAppFolderRelativePath, $"{ExecutableName}.desktop");

                    commands = new[]
                    {
                        "cd ~",
                        "sudo umount /mnt/c",
                        "sudo mount -t drvfs C: /mnt/c -o metadata",
                        $"cd {linuxPath}",
                        $"sudo find {Tools.LinuxPath(newFolderRelativePath)} -type f -exec chmod 644 {{}} \\;",
                        $"sudo find {Tools.LinuxPath(newFolderRelativePath)} -type f \\( -name 'wassabee' -o -name 'hwi' -o -name 'bitcoind' \\) -exec chmod +x {{}} \\;",
                        $"sudo chmod -R 0775 {Tools.LinuxPath(debianFolderRelativePath)}",
                        $"sudo chmod -R 0644 {debDestopFileLinuxPath}",
                        $"dpkg --build {Tools.LinuxPath(debFolderRelativePath)} $(pwd)"
                    };
                    arguments = string.Join(" && ", commands);
                    using (var process = Process.Start(new ProcessStartInfo
                    {
                        FileName = "wsl",
                        Arguments = arguments,
                        RedirectStandardInput = true,
                        WorkingDirectory = BinDistDirectory
                    }))
                    {
                        process.WaitForExit();
                    }

                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(debFolderPath).GetAwaiter().GetResult();

                    string oldDeb = Path.Combine(BinDistDirectory, $"{ExecutableName}_{VersionPrefix}_amd64.deb");
                    string newDeb = Path.Combine(BinDistDirectory, $"Wasabi-{VersionPrefix}.deb");
                    File.Move(oldDeb, newDeb);

                    IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult();
                    Console.WriteLine($"Deleted {publishedFolder}");
                }
            }
        }
        public static async Task <CoreNode> CreateAsync(CoreNodeParams coreNodeParams, CancellationToken cancel)
        {
            Guard.NotNull(nameof(coreNodeParams), coreNodeParams);
            using (BenchmarkLogger.Measure())
            {
                var coreNode = new CoreNode();
                coreNode.HostedServices = coreNodeParams.HostedServices;
                coreNode.DataDir        = coreNodeParams.DataDir;
                coreNode.Network        = coreNodeParams.Network;
                coreNode.MempoolService = coreNodeParams.MempoolService;

                var configPath = Path.Combine(coreNode.DataDir, "bitcoin.conf");
                coreNode.Config = new CoreConfig();
                if (File.Exists(configPath))
                {
                    var configString = await File.ReadAllTextAsync(configPath).ConfigureAwait(false);

                    coreNode.Config.AddOrUpdate(configString);                     // Bitcoin Core considers the last entry to be valid.
                }
                cancel.ThrowIfCancellationRequested();

                var configTranslator = new CoreConfigTranslator(coreNode.Config, coreNode.Network);

                string    rpcUser           = configTranslator.TryGetRpcUser();
                string    rpcPassword       = configTranslator.TryGetRpcPassword();
                string    rpcCookieFilePath = configTranslator.TryGetRpcCookieFile();
                string    rpcHost           = configTranslator.TryGetRpcBind();
                int?      rpcPort           = configTranslator.TryGetRpcPort();
                WhiteBind whiteBind         = configTranslator.TryGetWhiteBind();

                string authString;
                bool   cookieAuth = rpcCookieFilePath is { };
                if (cookieAuth)
                {
                    authString = $"cookiefile={rpcCookieFilePath}";
                }
                else
                {
                    rpcUser ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    rpcPassword ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    authString = $"{rpcUser}:{rpcPassword}";
                }

                coreNode.P2pEndPoint = whiteBind?.EndPoint ?? coreNodeParams.P2pEndPointStrategy.EndPoint;
                rpcHost ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetHostOrDefault();
                rpcPort ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetPortOrDefault();
                EndPointParser.TryParse($"{rpcHost}:{rpcPort}", coreNode.Network.RPCPort, out EndPoint rpce);
                coreNode.RpcEndPoint = rpce;

                var rpcClient = new RPCClient(
                    $"{authString}",
                    coreNode.RpcEndPoint.ToString(coreNode.Network.DefaultPort),
                    coreNode.Network);
                coreNode.RpcClient = new CachedRpcClient(rpcClient, coreNodeParams.Cache);

                if (coreNodeParams.TryRestart)
                {
                    await coreNode.TryStopAsync(false).ConfigureAwait(false);
                }
                cancel.ThrowIfCancellationRequested();

                if (coreNodeParams.TryDeleteDataDir)
                {
                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(coreNode.DataDir).ConfigureAwait(false);
                }
                cancel.ThrowIfCancellationRequested();

                IoHelpers.EnsureDirectoryExists(coreNode.DataDir);

                var configPrefix             = NetworkTranslator.GetConfigPrefix(coreNode.Network);
                var whiteBindPermissionsPart = !string.IsNullOrWhiteSpace(whiteBind?.Permissions) ? $"{whiteBind?.Permissions}@" : "";
                var desiredConfigLines       = new List <string>()
                {
                    $"{configPrefix}.server			= 1",
                    $"{configPrefix}.listen			= 1",
                    $"{configPrefix}.whitebind		= {whiteBindPermissionsPart}{coreNode.P2pEndPoint.ToString(coreNode.Network.DefaultPort)}",
                    $"{configPrefix}.rpcbind		= {coreNode.RpcEndPoint.GetHostOrDefault()}",
                    $"{configPrefix}.rpcallowip		= {IPAddress.Loopback}",
                    $"{configPrefix}.rpcport		= {coreNode.RpcEndPoint.GetPortOrDefault()}"
                };

                if (!cookieAuth)
                {
                    desiredConfigLines.Add($"{configPrefix}.rpcuser		= {coreNode.RpcClient.CredentialString.UserPassword.UserName}");
                    desiredConfigLines.Add($"{configPrefix}.rpcpassword	= {coreNode.RpcClient.CredentialString.UserPassword.Password}");
                }

                if (coreNodeParams.TxIndex is { })