public async Task CanLoadLegalDocsAsync() { var legalDir = Common.GetWorkDir(); if (Directory.Exists(legalDir)) { await IoHelpers.TryDeleteDirectoryAsync(legalDir); } Directory.CreateDirectory(legalDir); var res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); var version = new Version(1, 1); // Deletes them if multiple legal docs found. var candidate = File.Create(Path.Combine(legalDir, $"{version}.txt")); await candidate.DisposeAsync(); res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.NotNull(res); Assert.Single(Directory.GetFiles(legalDir)); Assert.Empty(Directory.GetDirectories(legalDir)); Assert.Equal(version, res?.Version); }
private volatile bool _disposedValue = false; // To detect redundant calls public RegTestFixture() { RuntimeParams.SetDataDir(Path.Combine(Common.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.TryDeleteDirectoryAsync(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:{CryptoHelpers.RandomInt(37130, 37999)}/"; BackendEndPointUri = new Uri(BackendEndPoint); BackendEndPointApiUri = new Uri(BackendEndPointUri, $"/api/v{Constants.BackendMajorVersion}/"); BackendHost = Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(webBuilder => webBuilder .UseStartup <Startup>() .UseConfiguration(conf) .UseWebRoot("../../../../WalletWasabi.Backend/wwwroot") .UseUrls(BackendEndPoint)) .Build(); Global = (Global)BackendHost.Services.GetService(typeof(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) }
public async Task ChecksConfigChangesAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); using WabiSabiCoordinator coordinator = new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore()); await coordinator.StartAsync(CancellationToken.None); var configPath = Path.Combine(workDir, "WabiSabiConfig.json"); WabiSabiConfig configChanger = new(configPath); configChanger.LoadOrCreateDefaultFile(); var newTarget = 729u; configChanger.ConfirmationTarget = newTarget; Assert.NotEqual(newTarget, coordinator.Config.ConfirmationTarget); configChanger.ToFile(); var configWatcher = coordinator.ConfigWatcher; await configWatcher.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); Assert.Equal(newTarget, coordinator.Config.ConfirmationTarget); // Do it one more time. newTarget = 372; configChanger.ConfirmationTarget = newTarget; Assert.NotEqual(newTarget, coordinator.Config.ConfirmationTarget); configChanger.ToFile(); await configWatcher.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); Assert.Equal(newTarget, coordinator.Config.ConfirmationTarget); await coordinator.StopAsync(CancellationToken.None); }
public async Task ReleasesInmatesAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); // Create prison. CoordinatorParameters coordinatorParameters = new(workDir); coordinatorParameters.RuntimeCoordinatorConfig.ReleaseUtxoFromPrisonAfter = TimeSpan.FromMilliseconds(1); using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig); await w.StartAsync(CancellationToken.None); var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var p = w.Prison; p.Punish(i1); p.Punish(i2); Assert.NotEmpty(p.GetInmates()); // Wait until releases from prison. await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); Assert.Empty(p.GetInmates()); await w.StopAsync(CancellationToken.None); }
public async Task LoadsConfigAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); // Create the config first with default value. using WabiSabiCoordinator coordinator = new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore()); await coordinator.StartAsync(CancellationToken.None); await coordinator.StopAsync(CancellationToken.None); // Change the file. var configPath = Path.Combine(workDir, "WabiSabiConfig.json"); WabiSabiConfig configChanger = new(configPath); configChanger.LoadOrCreateDefaultFile(); var newTarget = 729u; configChanger.ConfirmationTarget = newTarget; Assert.NotEqual(newTarget, coordinator.Config.ConfirmationTarget); configChanger.ToFile(); // Assert the new value is loaded and not the default one. using WabiSabiCoordinator coordinator2 = new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore()); await coordinator2.StartAsync(CancellationToken.None); Assert.Equal(newTarget, coordinator2.Config.ConfirmationTarget); await coordinator2.StopAsync(CancellationToken.None); }
public async Task NoPrisonSerializationAsync() { // Don't serialize when there's no change. var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); // Create prison. CoordinatorParameters coordinatorParameters = new(workDir); using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig); await w.StartAsync(CancellationToken.None); var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); w.Prison.Punish(i1); w.Prison.Punish(i2); // Wait until serializes. await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); // Make sure it does not serialize again as there was no change. File.Delete(w.PrisonFilePath); await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); Assert.False(File.Exists(w.PrisonFilePath)); await w.StopAsync(CancellationToken.None); }
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.TryDeleteDirectoryAsync(walletsPath); await IoHelpers.TryDeleteDirectoryAsync(walletsBackupPath); return(walletsPath, walletsBackupPath); }
private static async Task SignAsync() { 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.Copy(msiPath, newMsiPath); Console.Write("Enter Code Signing Certificate Password: "******"cmd", BinDistDirectory, $"signtool sign /d \"Wasabi Wallet\" /f \"{PfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit"); await IoHelpers.TryDeleteDirectoryAsync(publishedFolder).ConfigureAwait(false); Console.WriteLine($"Deleted {publishedFolder}"); } else if (target.StartsWith("osx", StringComparison.OrdinalIgnoreCase)) { string dmgFilePath = Path.Combine(BinDistDirectory, $"Wasabi-{VersionPrefix}.dmg"); if (!File.Exists(dmgFilePath)) { throw new Exception(".dmg does not exist."); } string zipFilePath = Path.Combine(BinDistDirectory, $"Wasabi-osx-{VersionPrefix}.zip"); if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } } } Console.WriteLine("Signing final files..."); var finalFiles = Directory.GetFiles(BinDistDirectory); foreach (var finalFile in finalFiles) { StartProcessAndWaitForExit("cmd", BinDistDirectory, $"gpg --armor --detach-sign {finalFile} && exit"); StartProcessAndWaitForExit("cmd", WixProjectDirectory, $"git checkout -- ComponentsGenerated.wxs && exit"); } IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); }
private async Task <(string dir, string matureFilters, string immatureFilters)> GetIndexStorePathsAsync([CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "") { var dir = Path.Combine(Common.GetWorkDir(callerFilePath, callerMemberName), "IndexStore"); await IoHelpers.TryDeleteDirectoryAsync(dir); var matureFilters = Path.Combine(dir, "MatureIndex.dat"); var immatureFilters = Path.Combine(dir, "ImmatureIndex.dat"); IoHelpers.EnsureContainingDirectoryExists(matureFilters); IoHelpers.EnsureContainingDirectoryExists(immatureFilters); return(dir, matureFilters, immatureFilters); }
public async Task CanStartAndStopAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig); await w.StartAsync(CancellationToken.None); await w.StopAsync(CancellationToken.None); }
public async Task CanLiveAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); using WabiSabiCoordinator coordinator = new(coordinatorParameters, NewMockRpcClient()); await coordinator.StartAsync(CancellationToken.None); await coordinator.StopAsync(CancellationToken.None); }
public async Task CreatesConfigAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); using WabiSabiCoordinator coordinator = new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore()); await coordinator.StartAsync(CancellationToken.None); Assert.True(File.Exists(Path.Combine(workDir, "WabiSabiConfig.json"))); await coordinator.StopAsync(CancellationToken.None); }
public async Task ResolvesConflictsAsync() { var legalDir = Common.GetWorkDir(); if (Directory.Exists(legalDir)) { await IoHelpers.TryDeleteDirectoryAsync(legalDir); } Directory.CreateDirectory(legalDir); var res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); // Deletes them if multiple legal docs found. var candidate1 = File.Create(Path.Combine(legalDir, "1.1.txt")); var candidate2 = File.Create(Path.Combine(legalDir, "1.2.txt")); await candidate1.DisposeAsync(); await candidate2.DisposeAsync(); res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); Assert.Empty(Directory.GetFiles(legalDir)); Assert.Empty(Directory.GetDirectories(legalDir)); // Only the candidates are deleted. var trash = File.Create(Path.Combine(legalDir, "1.txt")); candidate1 = File.Create(Path.Combine(legalDir, "1.1.txt")); candidate2 = File.Create(Path.Combine(legalDir, "1.2.txt")); await trash.DisposeAsync(); await candidate1.DisposeAsync(); await candidate2.DisposeAsync(); res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); Assert.Single(Directory.GetFiles(legalDir)); Assert.Empty(Directory.GetDirectories(legalDir)); }
public async Task CanCancelAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); using WabiSabiCoordinator coordinator = new(coordinatorParameters, NewMockRpcClient()); using CancellationTokenSource cts = new(); cts.Cancel(); await coordinator.StartAsync(cts.Token); await coordinator.StopAsync(CancellationToken.None); using WabiSabiCoordinator coordinator2 = new(coordinatorParameters, NewMockRpcClient()); using CancellationTokenSource cts2 = new(); await coordinator2.StartAsync(cts2.Token); cts2.Cancel(); await coordinator2.StopAsync(CancellationToken.None); using WabiSabiCoordinator coordinator3 = new(coordinatorParameters, NewMockRpcClient()); using CancellationTokenSource cts3 = new(); var t = coordinator3.StartAsync(cts3.Token); cts3.Cancel(); await t; await coordinator3.StopAsync(CancellationToken.None); using WabiSabiCoordinator coordinator4 = new(coordinatorParameters, NewMockRpcClient()); await coordinator4.StartAsync(CancellationToken.None); using CancellationTokenSource cts4 = new(); cts4.Cancel(); await coordinator4.StopAsync(cts4.Token); using WabiSabiCoordinator coordinator5 = new(coordinatorParameters, NewMockRpcClient()); await coordinator5.StartAsync(CancellationToken.None); using CancellationTokenSource cts5 = new(); t = coordinator5.StopAsync(cts5.Token); cts5.Cancel(); await t; }
public async Task PrisonSerializationAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); // Create prison. CoordinatorParameters coordinatorParameters = new(workDir); using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig); await w.StartAsync(CancellationToken.None); var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero); w.Prison.Punish(i1); w.Prison.Punish(i2); // Wait until serializes. await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7)); await w.StopAsync(CancellationToken.None); // See if prev UTXOs are loaded. CoordinatorParameters coordinatorParameters2 = new(workDir); using var w2 = new Warden(coordinatorParameters2.UtxoWardenPeriod, coordinatorParameters2.PrisonFilePath, coordinatorParameters2.RuntimeCoordinatorConfig); await w2.StartAsync(CancellationToken.None); Assert.True(w2.Prison.TryGet(i1.Utxo, out var sameI1)); Assert.True(w2.Prison.TryGet(i2.Utxo, out var sameI2)); Assert.Equal(i1.LastDisruptedRoundId, sameI1 !.LastDisruptedRoundId); Assert.Equal(i2.LastDisruptedRoundId, sameI2 !.LastDisruptedRoundId); Assert.Equal(i1.Punishment, sameI1 !.Punishment); Assert.Equal(i2.Punishment, sameI2 !.Punishment); Assert.Equal(i1.Started, sameI1 !.Started); Assert.Equal(i2.Started, sameI2 !.Started); await w2.StopAsync(CancellationToken.None); }
public async Task LeavesTrashAloneAsync() { var legalDir = Common.GetWorkDir(); if (Directory.Exists(legalDir)) { await IoHelpers.TryDeleteDirectoryAsync(legalDir); } Directory.CreateDirectory(legalDir); var res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); // Leaves one trash alone. var trash1 = File.Create(Path.Combine(legalDir, "foo")); await trash1.DisposeAsync(); res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); Assert.Single(Directory.GetFiles(legalDir)); Assert.Empty(Directory.GetDirectories(legalDir)); // Leaves 3 trash alone. var trash2 = File.Create(Path.Combine(legalDir, "foo.txt")); var trash3 = File.Create(Path.Combine(legalDir, "foo2")); await trash2.DisposeAsync(); await trash3.DisposeAsync(); res = await LegalDocuments.LoadAgreedAsync(legalDir); Assert.Null(res); Assert.Equal(3, Directory.GetFiles(legalDir).Length); Assert.Empty(Directory.GetDirectories(legalDir)); }
public async Task LoadsIncompleteConfigAsync() { var workDir = Common.GetWorkDir(); await IoHelpers.TryDeleteDirectoryAsync(workDir); CoordinatorParameters coordinatorParameters = new(workDir); // Create the config first with default value. using WabiSabiCoordinator coordinator = new(coordinatorParameters, NewMockRpcClient(), new CoinJoinIdStore()); await coordinator.StartAsync(CancellationToken.None); await coordinator.StopAsync(CancellationToken.None); // Remove a line. var configPath = Path.Combine(workDir, "WabiSabiConfig.json"); var lines = File.ReadAllLines(configPath); var incompleteLines = lines.Where(x => !x.Contains("ReleaseUtxoFromPrisonAfter", StringComparison.Ordinal)).ToArray(); Assert.NotEqual(lines.Length, incompleteLines.Length); File.WriteAllLines(configPath, incompleteLines); // Assert the new default value is loaded. CoordinatorParameters coordinatorParameters2 = new(workDir); using WabiSabiCoordinator coordinator2 = new(coordinatorParameters2, NewMockRpcClient(), new CoinJoinIdStore()); await coordinator2.StartAsync(CancellationToken.None); var defaultValue = TimeSpanJsonConverter.Parse("0d 3h 0m 0s"); Assert.Equal(TimeSpan.FromHours(3), defaultValue); Assert.Equal(defaultValue, coordinator2.Config.ReleaseUtxoFromPrisonAfter); await coordinator2.StopAsync(CancellationToken.None); // Assert the new default value is serialized. lines = File.ReadAllLines(configPath); Assert.Contains(lines, x => x.Contains("\"ReleaseUtxoFromPrisonAfter\": \"0d 3h 0m 0s\"", StringComparison.Ordinal)); }
private static void CreateDigests() { var tempDir = "DigestTempDir"; IoHelpers.TryDeleteDirectoryAsync(tempDir).GetAwaiter().GetResult(); Directory.CreateDirectory(tempDir); var torDaemonsDir = Path.Combine(LibraryProjectDirectory, "TorDaemons"); string torWinZip = Path.Combine(torDaemonsDir, "tor-win64.zip"); IoHelpers.BetterExtractZipToDirectoryAsync(torWinZip, tempDir).GetAwaiter().GetResult(); 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().GetResult(); File.Move(Path.Combine(tempDir, "Tor", "tor"), Path.Combine(tempDir, "TorLin")); string torOsxZip = Path.Combine(torDaemonsDir, "tor-osx64.zip"); IoHelpers.BetterExtractZipToDirectoryAsync(torOsxZip, tempDir).GetAwaiter().GetResult(); File.Move(Path.Combine(tempDir, "Tor", "tor.real"), Path.Combine(tempDir, "TorOsx")); 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.TryDeleteDirectoryAsync(tempDir).GetAwaiter().GetResult(); }
private static async Task PublishAsync() { if (Directory.Exists(BinDistDirectory)) { await IoHelpers.TryDeleteDirectoryAsync(BinDistDirectory).ConfigureAwait(false); Console.WriteLine($"Deleted {BinDistDirectory}"); } StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "clean --configuration Release"); var desktopBinReleaseDirectory = Path.GetFullPath(Path.Combine(DesktopProjectDirectory, "bin", "Release")); var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(LibraryProjectDirectory, "bin", "Release")); if (Directory.Exists(desktopBinReleaseDirectory)) { await IoHelpers.TryDeleteDirectoryAsync(desktopBinReleaseDirectory).ConfigureAwait(false); Console.WriteLine($"Deleted {desktopBinReleaseDirectory}"); } if (Directory.Exists(libraryBinReleaseDirectory)) { await IoHelpers.TryDeleteDirectoryAsync(libraryBinReleaseDirectory).ConfigureAwait(false); Console.WriteLine($"Deleted {libraryBinReleaseDirectory}"); } var deterministicFileNameTag = IsContinuousDelivery ? $"{DateTimeOffset.UtcNow:ddMMyyyy}{DateTimeOffset.UtcNow.TimeOfDay.TotalSeconds}" : VersionPrefix; var deliveryPath = IsContinuousDelivery ? Path.Combine(BinDistDirectory, "cdelivery") : BinDistDirectory; IoHelpers.EnsureDirectoryExists(deliveryPath); Console.WriteLine($"Binaries will be delivered here: {deliveryPath}"); string buildInfoJson = GetBuildInfoData(); CheckUncommittedGitChanges(); 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}"); } string buildInfoPath = Path.Combine(currentBinDistDirectory, "BUILDINFO.json"); File.WriteAllText(buildInfoPath, buildInfoJson); StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "clean"); // 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 string dotnetProcessArgs = string.Join( " ", $"publish", $"--configuration Release", $"--force", $"--output \"{currentBinDistDirectory}\"", $"--self-contained true", $"--runtime \"{target}\"", $"--disable-parallel", $"--no-cache", $"/p:VersionPrefix={VersionPrefix}", $"/p:DebugType=none", $"/p:DebugSymbols=false", $"/p:ErrorReport=none", $"/p:DocumentationFile=\"\"", $"/p:Deterministic=true", $"/p:RestoreLockedMode=true"); StartProcessAndWaitForExit( "dotnet", DesktopProjectDirectory, arguments: dotnetProcessArgs, redirectStandardOutput: true); Tools.ClearSha512Tags(currentBinDistDirectory); // Remove Tor binaries that are not relevant to the platform. var toNotRemove = ""; if (target.StartsWith("win")) { toNotRemove = "win"; } else if (target.StartsWith("linux")) { toNotRemove = "lin"; } else if (target.StartsWith("osx")) { toNotRemove = "osx"; } // 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)) { await IoHelpers.TryDeleteDirectoryAsync(dir.FullName).ConfigureAwait(false); } } // Rename the final exe. string oldExecutablePath; string newExecutablePath; if (target.StartsWith("win")) { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent.Desktop.exe"); newExecutablePath = Path.Combine(currentBinDistDirectory, $"{ExecutableName}.exe"); // Delete unused executables. File.Delete(Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent.exe")); } else // Linux & OSX { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent.Desktop"); newExecutablePath = Path.Combine(currentBinDistDirectory, ExecutableName); // Delete unused executables. File.Delete(Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent")); } File.Move(oldExecutablePath, newExecutablePath); long installedSizeKb = Tools.DirSize(new DirectoryInfo(publishedFolder)) / 1000; if (target.StartsWith("win")) { // 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. } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{target}.zip")); if (IsContinuousDelivery) { continue; } } else if (target.StartsWith("osx")) { // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!! if (OnlyBinaries) { continue; } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{target}.zip")); if (IsContinuousDelivery) { continue; } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(BinDistDirectory, $"Wasabi-osx-{VersionPrefix}.zip")); await IoHelpers.TryDeleteDirectoryAsync(currentBinDistDirectory).ConfigureAwait(false); Console.WriteLine($"Deleted {currentBinDistDirectory}"); } else if (target.StartsWith("linux")) { // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!! if (OnlyBinaries) { continue; } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{target}.zip")); if (IsContinuousDelivery) { continue; } Console.WriteLine("Create Linux .tar.gz"); if (!Directory.Exists(publishedFolder)) { throw new Exception($"{publishedFolder} does not exist."); } var newFolderName = $"Wasabi-{VersionPrefix}"; var newFolderPath = Path.Combine(BinDistDirectory, newFolderName); Directory.Move(publishedFolder, newFolderPath); publishedFolder = newFolderPath; var driveLetterUpper = BinDistDirectory[0]; var driveLetterLower = char.ToLower(driveLetterUpper); var linuxPath = $"/mnt/{driveLetterLower}/{Tools.LinuxPath(BinDistDirectory[3..])}";
private static async Task PublishAsync() { if (Directory.Exists(BinDistDirectory)) { await IoHelpers.TryDeleteDirectoryAsync(BinDistDirectory).ConfigureAwait(false); Console.WriteLine($"# Deleted {BinDistDirectory}"); } Console.WriteLine($"# Run dotnet restore"); StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "restore --locked-mode"); Console.WriteLine($"# Run dotnet clean"); StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "clean --configuration Release"); string desktopBinReleaseDirectory = Path.GetFullPath(Path.Combine(DesktopProjectDirectory, "bin", "Release")); string libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(LibraryProjectDirectory, "bin", "Release")); if (Directory.Exists(desktopBinReleaseDirectory)) { await IoHelpers.TryDeleteDirectoryAsync(desktopBinReleaseDirectory).ConfigureAwait(false); Console.WriteLine($"#Deleted {desktopBinReleaseDirectory}"); } if (Directory.Exists(libraryBinReleaseDirectory)) { await IoHelpers.TryDeleteDirectoryAsync(libraryBinReleaseDirectory).ConfigureAwait(false); Console.WriteLine($"# Deleted {libraryBinReleaseDirectory}"); } var deterministicFileNameTag = IsContinuousDelivery ? $"{DateTimeOffset.UtcNow:ddMMyyyy}{DateTimeOffset.UtcNow.TimeOfDay.TotalSeconds}" : VersionPrefix; var deliveryPath = IsContinuousDelivery ? Path.Combine(BinDistDirectory, "cdelivery") : BinDistDirectory; IoHelpers.EnsureDirectoryExists(deliveryPath); Console.WriteLine($"# Binaries will be delivered here: {deliveryPath}"); string buildInfoJson = GetBuildInfoData(); CheckUncommittedGitChanges(); 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}"); } string buildInfoPath = Path.Combine(currentBinDistDirectory, "BUILDINFO.json"); File.WriteAllText(buildInfoPath, buildInfoJson); StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "clean"); // See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish for details. string dotnetProcessArgs = string.Join( " ", $"publish", $"--configuration Release", $"--force", $"--output \"{currentBinDistDirectory}\"", $"--self-contained true", $"--runtime \"{target}\"", $"--disable-parallel", $"--no-cache", $"--no-restore", $"/p:VersionPrefix={VersionPrefix}", $"/p:DebugType=none", $"/p:DebugSymbols=false", $"/p:ErrorReport=none", $"/p:DocumentationFile=\"\"", $"/p:Deterministic=true"); StartProcessAndWaitForExit( "dotnet", DesktopProjectDirectory, arguments: dotnetProcessArgs, redirectStandardOutput: true); Tools.ClearSha512Tags(currentBinDistDirectory); // Remove Tor binaries that are not relevant to the platform. var toNotRemove = ""; if (target.StartsWith("win")) { toNotRemove = "win"; } else if (target.StartsWith("linux")) { toNotRemove = "lin"; } else if (target.StartsWith("osx")) { toNotRemove = "osx"; } // 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)) { await IoHelpers.TryDeleteDirectoryAsync(dir.FullName).ConfigureAwait(false); } } // Rename the final exe. string oldExecutablePath; string newExecutablePath; if (target.StartsWith("win")) { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent.Desktop.exe"); newExecutablePath = Path.Combine(currentBinDistDirectory, $"{ExecutableName}.exe"); // Delete unused executables. File.Delete(Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent.exe")); } else // Linux & OSX { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent.Desktop"); newExecutablePath = Path.Combine(currentBinDistDirectory, ExecutableName); // Delete unused executables. File.Delete(Path.Combine(currentBinDistDirectory, "WalletWasabi.Fluent")); } File.Move(oldExecutablePath, newExecutablePath); long installedSizeKb = Tools.DirSize(new DirectoryInfo(publishedFolder)) / 1000; if (target.StartsWith("win")) { // 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. } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{GetPackageTargetPostfix(target)}.zip")); if (IsContinuousDelivery) { continue; } } else if (target.StartsWith("osx")) { // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!! if (OnlyBinaries) { continue; } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{GetPackageTargetPostfix(target)}.zip")); if (IsContinuousDelivery) { continue; } // Only add postfix to the final package if arm64, otherwise nothing. var postfix = target.Contains("arm64") ? "-arm64" : ""; // After notarization this will be the filename of the dmg file. var zipFileName = $"WasabiToNotarize-{deterministicFileNameTag}{postfix}.zip"; var zipFilePath = Path.Combine(BinDistDirectory, zipFileName); ZipFile.CreateFromDirectory(currentBinDistDirectory, zipFilePath); await IoHelpers.TryDeleteDirectoryAsync(currentBinDistDirectory).ConfigureAwait(false); Console.WriteLine($"# Deleted {currentBinDistDirectory}"); try { var drive = Tools.GetSingleUsbDrive(); var targetFilePath = Path.Combine(drive, zipFileName); Console.WriteLine($"# Trying to move unsigned zip file to removable ('{targetFilePath}')."); File.Move(zipFilePath, targetFilePath, overwrite: true); } catch (Exception ex) { Console.WriteLine($"# There was an error during copying the file to removable: '{ex.Message}'"); } } else if (target.StartsWith("linux")) { // IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!! if (OnlyBinaries) { continue; } ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{GetPackageTargetPostfix(target)}.zip")); if (IsContinuousDelivery) { continue; } Console.WriteLine("# Create Linux .tar.gz"); if (!Directory.Exists(publishedFolder)) { throw new Exception($"{publishedFolder} does not exist."); } var newFolderName = $"Wasabi-{VersionPrefix}"; var newFolderPath = Path.Combine(BinDistDirectory, newFolderName); Directory.Move(publishedFolder, newFolderPath); publishedFolder = newFolderPath; var driveLetterUpper = BinDistDirectory[0]; var driveLetterLower = char.ToLower(driveLetterUpper); var linuxPath = $"/mnt/{driveLetterLower}/{Tools.LinuxPath(BinDistDirectory[3..])}";
private static void Publish() { if (Directory.Exists(BinDistDirectory)) { IoHelpers.TryDeleteDirectoryAsync(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.TryDeleteDirectoryAsync(guiBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {guiBinReleaseDirectory}"); } if (Directory.Exists(libraryBinReleaseDirectory)) { IoHelpers.TryDeleteDirectoryAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {libraryBinReleaseDirectory}"); } var deterministicFileNameTag = IsContinuousDelivery ? $"{DateTimeOffset.UtcNow:ddMMyyyy}{DateTimeOffset.UtcNow.TimeOfDay.TotalSeconds}" : VersionPrefix; var deliveryPath = IsContinuousDelivery ? Path.Combine(BinDistDirectory, "cdelivery") : BinDistDirectory; IoHelpers.EnsureDirectoryExists(deliveryPath); Console.WriteLine($"Binaries will be delivered here: {deliveryPath}"); 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 = string.Join(" ", $"publish", $"--configuration Release", $"--force", $"--output \"{currentBinDistDirectory}\"", $"--self-contained true", $"--runtime \"{target}\"", $"--disable-parallel", $"--no-cache", $"/p:VersionPrefix={VersionPrefix}", $"/p:DebugType=none", $"/p:DebugSymbols=false", $"/p:ErrorReport=none", $"/p:DocumentationFile=\"\"", $"/p:Deterministic=true", $"/p:RestoreLockedMode=true"), WorkingDirectory = GuiProjectDirectory, RedirectStandardOutput = true })) { string error = process.StandardOutput.ReadToEnd(); process.WaitForExit(); if (process.ExitCode != 0) { throw new InvalidOperationException($"dotnet publish returned with error code {process.ExitCode}. Error message was: {error ?? "none"}"); } } 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.TryDeleteDirectoryAsync(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 daemonExePath = newExecutablePath[0..^ 4] + "d.exe";
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", "GroestlMix.msi"); if (!File.Exists(msiPath)) { throw new Exception(".msi does not exist. Expected path: GroestlMix.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 \"GroestlMix Wallet\" /f \"{PfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit"); process.WaitForExit(); } IoHelpers.TryDeleteDirectoryAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } else if (target.StartsWith("osx", StringComparison.OrdinalIgnoreCase)) { string dmgFilePath = Path.Combine(BinDistDirectory, $"Wasabi-{VersionPrefix}.dmg"); if (!File.Exists(dmgFilePath)) { throw new Exception(".dmg does not exist."); } string zipFilePath = Path.Combine(BinDistDirectory, $"Wasabi-osx-{VersionPrefix}.zip"); if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } } } 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); }
public static async Task <CoreNode> CreateAsync(CoreNodeParams coreNodeParams, CancellationToken cancel) { Guard.NotNull(nameof(coreNodeParams), coreNodeParams); using (BenchmarkLogger.Measure()) { var coreNode = new CoreNode { HostedServices = coreNodeParams.HostedServices, DataDir = coreNodeParams.DataDir, Network = coreNodeParams.Network, 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, cancel).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; if (rpcHost is null) { coreNodeParams.RpcEndPointStrategy.EndPoint.TryGetHost(out rpcHost); } if (rpcPort is null) { coreNodeParams.RpcEndPointStrategy.EndPoint.TryGetPort(out rpcPort); } 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.TryDeleteDirectoryAsync(coreNode.DataDir).ConfigureAwait(false); } cancel.ThrowIfCancellationRequested(); IoHelpers.EnsureDirectoryExists(coreNode.DataDir); var configPrefix = NetworkTranslator.GetConfigPrefix(coreNode.Network); var whiteBindPermissionsPart = !string.IsNullOrWhiteSpace(whiteBind?.Permissions) ? $"{whiteBind?.Permissions}@" : ""; if (!coreNode.RpcEndPoint.TryGetHost(out string?rpcBindParameter) || !coreNode.RpcEndPoint.TryGetPort(out int?rpcPortParameter)) { throw new ArgumentException("Endpoint type is not supported.", nameof(coreNode.RpcEndPoint)); } var desiredConfigLines = new List <string>() { $"{configPrefix}.server = 1", $"{configPrefix}.listen = 1", $"{configPrefix}.whitebind = {whiteBindPermissionsPart}{coreNode.P2pEndPoint.ToString(coreNode.Network.DefaultPort)}", $"{configPrefix}.rpcbind = {rpcBindParameter}", $"{configPrefix}.rpcallowip = {IPAddress.Loopback}", $"{configPrefix}.rpcport = {rpcPortParameter}" }; if (!cookieAuth) { desiredConfigLines.Add($"{configPrefix}.rpcuser = {coreNode.RpcClient.CredentialString.UserPassword.UserName}"); desiredConfigLines.Add($"{configPrefix}.rpcpassword = {coreNode.RpcClient.CredentialString.UserPassword.Password}"); } if (coreNodeParams.TxIndex is { })