Release Vexta CPU Miner v0.1.2
This commit is contained in:
parent
17949bc516
commit
d3b9876b45
3 changed files with 399 additions and 10 deletions
347
Program.cs
347
Program.cs
|
|
@ -1,12 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -85,10 +87,11 @@ internal static class Program
|
||||||
password = GetArg(args, "-p") ?? "x";
|
password = GetArg(args, "-p") ?? "x";
|
||||||
|
|
||||||
var threadText = GetArg(args, "-t");
|
var threadText = GetArg(args, "-t");
|
||||||
|
var threadsAuto = threadText == null;
|
||||||
|
|
||||||
threadCount = threadText != null
|
threadCount = threadsAuto
|
||||||
? int.Parse(threadText, CultureInfo.InvariantCulture)
|
? GetPhysicalCoreCount()
|
||||||
: Environment.ProcessorCount;
|
: int.Parse(threadText!, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
if(threadCount < 1)
|
if(threadCount < 1)
|
||||||
throw new ArgumentException("Thread count must be at least 1");
|
throw new ArgumentException("Thread count must be at least 1");
|
||||||
|
|
@ -125,9 +128,12 @@ internal static class Program
|
||||||
};
|
};
|
||||||
|
|
||||||
PrintBanner();
|
PrintBanner();
|
||||||
|
PrintStartupDiagnostics();
|
||||||
Console.WriteLine($"Pool : {host}:{port}");
|
Console.WriteLine($"Pool : {host}:{port}");
|
||||||
Console.WriteLine($"Worker : {worker}");
|
Console.WriteLine($"Worker : {worker}");
|
||||||
Console.WriteLine($"Threads : {threadCount}");
|
Console.WriteLine(
|
||||||
|
$"Mining Threads : {threadCount}" +
|
||||||
|
(threadsAuto ? " (auto)" : " (manual)"));
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
var statsTask = StatsLoopAsync(shutdown.Token);
|
var statsTask = StatsLoopAsync(shutdown.Token);
|
||||||
|
|
@ -814,6 +820,235 @@ internal static class Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void PrintStartupDiagnostics()
|
||||||
|
{
|
||||||
|
var logicalCpus = Environment.ProcessorCount;
|
||||||
|
var physicalCores = GetPhysicalCoreCount();
|
||||||
|
var cpuModel = GetCpuModel();
|
||||||
|
var aesSupported = GetAesSupport();
|
||||||
|
var hugePages = GetHugePagesStatus();
|
||||||
|
|
||||||
|
string randomXStatus;
|
||||||
|
string randomXPath;
|
||||||
|
|
||||||
|
if(OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
// Accessing these properties initializes VextaRandomX and
|
||||||
|
// explicitly loads librandomx.so from the miner directory.
|
||||||
|
randomXStatus = VextaRandomX.NativeLibraryLoaded
|
||||||
|
? "Loaded OK"
|
||||||
|
: "Not loaded";
|
||||||
|
|
||||||
|
randomXPath = VextaRandomX.NativeLibraryPath ?? "Unknown";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
randomXStatus = "System loader";
|
||||||
|
randomXPath = "Platform default";
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"CPU : {cpuModel}");
|
||||||
|
Console.WriteLine($"Physical Cores : {physicalCores}");
|
||||||
|
Console.WriteLine($"Logical CPUs : {logicalCpus}");
|
||||||
|
Console.WriteLine($"AES : {aesSupported}");
|
||||||
|
Console.WriteLine($"Huge Pages : {hugePages}");
|
||||||
|
Console.WriteLine($"RandomX Library: {randomXStatus}");
|
||||||
|
Console.WriteLine($"Library Path : {randomXPath}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetCpuModel()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(OperatingSystem.IsLinux() && File.Exists("/proc/cpuinfo"))
|
||||||
|
{
|
||||||
|
foreach(var line in File.ReadLines("/proc/cpuinfo"))
|
||||||
|
{
|
||||||
|
if(line.StartsWith("model name", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var colon = line.IndexOf(':');
|
||||||
|
|
||||||
|
if(colon >= 0)
|
||||||
|
return line[(colon + 1)..].Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var identifier = Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER");
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(identifier))
|
||||||
|
return identifier.Trim();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetPhysicalCoreCount()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(OperatingSystem.IsLinux() && File.Exists("/proc/cpuinfo"))
|
||||||
|
{
|
||||||
|
var cores = new HashSet<string>();
|
||||||
|
string? physicalId = null;
|
||||||
|
string? coreId = null;
|
||||||
|
|
||||||
|
foreach(var rawLine in File.ReadLines("/proc/cpuinfo"))
|
||||||
|
{
|
||||||
|
var line = rawLine.Trim();
|
||||||
|
|
||||||
|
if(line.Length == 0)
|
||||||
|
{
|
||||||
|
if(physicalId != null && coreId != null)
|
||||||
|
cores.Add($"{physicalId}:{coreId}");
|
||||||
|
|
||||||
|
physicalId = null;
|
||||||
|
coreId = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.StartsWith("physical id", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var colon = line.IndexOf(':');
|
||||||
|
|
||||||
|
if(colon >= 0)
|
||||||
|
physicalId = line[(colon + 1)..].Trim();
|
||||||
|
}
|
||||||
|
else if(line.StartsWith("core id", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var colon = line.IndexOf(':');
|
||||||
|
|
||||||
|
if(colon >= 0)
|
||||||
|
coreId = line[(colon + 1)..].Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(physicalId != null && coreId != null)
|
||||||
|
cores.Add($"{physicalId}:{coreId}");
|
||||||
|
|
||||||
|
if(cores.Count > 0)
|
||||||
|
return cores.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
var windowsCores = GetWindowsPhysicalCoreCount();
|
||||||
|
|
||||||
|
if(windowsCores > 0)
|
||||||
|
return windowsCores;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return Environment.ProcessorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetWindowsPhysicalCoreCount()
|
||||||
|
{
|
||||||
|
uint length = 0;
|
||||||
|
|
||||||
|
GetLogicalProcessorInformation(IntPtr.Zero, ref length);
|
||||||
|
|
||||||
|
if(length == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var buffer = Marshal.AllocHGlobal((int)length);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!GetLogicalProcessorInformation(buffer, ref length))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// SYSTEM_LOGICAL_PROCESSOR_INFORMATION is 32 bytes on x64
|
||||||
|
// and 24 bytes on x86.
|
||||||
|
var entrySize = IntPtr.Size == 8 ? 32 : 24;
|
||||||
|
var relationshipOffset = IntPtr.Size;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
for(var offset = 0;
|
||||||
|
offset + entrySize <= length;
|
||||||
|
offset += entrySize)
|
||||||
|
{
|
||||||
|
var relationship = Marshal.ReadInt32(
|
||||||
|
buffer,
|
||||||
|
offset + relationshipOffset);
|
||||||
|
|
||||||
|
// RelationProcessorCore = 0
|
||||||
|
if(relationship == 0)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static extern bool GetLogicalProcessorInformation(
|
||||||
|
IntPtr buffer,
|
||||||
|
ref uint returnedLength);
|
||||||
|
|
||||||
|
private static string GetAesSupport()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(System.Runtime.Intrinsics.X86.Aes.IsSupported)
|
||||||
|
return "Supported";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Not detected";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetHugePagesStatus()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(OperatingSystem.IsLinux() && File.Exists("/proc/meminfo"))
|
||||||
|
{
|
||||||
|
foreach(var line in File.ReadLines("/proc/meminfo"))
|
||||||
|
{
|
||||||
|
if(!line.StartsWith("HugePages_Total:", StringComparison.Ordinal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var value = line["HugePages_Total:".Length..].Trim();
|
||||||
|
var parts = value.Split(
|
||||||
|
' ',
|
||||||
|
StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
if(parts.Length > 0 &&
|
||||||
|
long.TryParse(
|
||||||
|
parts[0],
|
||||||
|
NumberStyles.Integer,
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
out var total))
|
||||||
|
{
|
||||||
|
return total > 0
|
||||||
|
? $"Configured ({total})"
|
||||||
|
: "Not configured";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task StatsLoopAsync(CancellationToken ct)
|
private static async Task StatsLoopAsync(CancellationToken ct)
|
||||||
{
|
{
|
||||||
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
|
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
|
||||||
|
|
@ -823,6 +1058,10 @@ internal static class Program
|
||||||
var lastTime = sw.Elapsed;
|
var lastTime = sw.Elapsed;
|
||||||
var measuring = false;
|
var measuring = false;
|
||||||
|
|
||||||
|
var averageHistory = new List<(TimeSpan Time, long Hashes)>();
|
||||||
|
TimeSpan? averageStartTime = null;
|
||||||
|
var nextAverageReport = TimeSpan.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while(await timer.WaitForNextTickAsync(ct))
|
while(await timer.WaitForNextTickAsync(ct))
|
||||||
|
|
@ -830,6 +1069,34 @@ internal static class Program
|
||||||
var now = sw.Elapsed;
|
var now = sw.Elapsed;
|
||||||
var hashes = Interlocked.Read(ref totalHashes);
|
var hashes = Interlocked.Read(ref totalHashes);
|
||||||
|
|
||||||
|
if(hashes > 0)
|
||||||
|
{
|
||||||
|
if(averageStartTime == null)
|
||||||
|
{
|
||||||
|
averageStartTime = now;
|
||||||
|
nextAverageReport = now + TimeSpan.FromMinutes(1);
|
||||||
|
averageHistory.Add((now, hashes));
|
||||||
|
}
|
||||||
|
else if(now >= nextAverageReport)
|
||||||
|
{
|
||||||
|
averageHistory.Add((now, hashes));
|
||||||
|
|
||||||
|
WriteAverageHashrate(
|
||||||
|
now,
|
||||||
|
hashes,
|
||||||
|
averageHistory,
|
||||||
|
averageStartTime.Value);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nextAverageReport += TimeSpan.FromMinutes(1);
|
||||||
|
}
|
||||||
|
while(nextAverageReport <= now);
|
||||||
|
|
||||||
|
TrimAverageHistory(now, averageHistory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(hashes == 0)
|
if(hashes == 0)
|
||||||
{
|
{
|
||||||
lastHashes = hashes;
|
lastHashes = hashes;
|
||||||
|
|
@ -877,6 +1144,74 @@ internal static class Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void WriteAverageHashrate(
|
||||||
|
TimeSpan now,
|
||||||
|
long hashes,
|
||||||
|
List<(TimeSpan Time, long Hashes)> history,
|
||||||
|
TimeSpan startTime)
|
||||||
|
{
|
||||||
|
var avg5 = FormatAverageWindow(
|
||||||
|
now, hashes, history, startTime, TimeSpan.FromMinutes(5));
|
||||||
|
|
||||||
|
var avg15 = FormatAverageWindow(
|
||||||
|
now, hashes, history, startTime, TimeSpan.FromMinutes(15));
|
||||||
|
|
||||||
|
var avg60 = FormatAverageWindow(
|
||||||
|
now, hashes, history, startTime, TimeSpan.FromMinutes(60));
|
||||||
|
|
||||||
|
WriteColor(
|
||||||
|
$"AVG HASHRATE 5m:{avg5} 15m:{avg15} 60m:{avg60}",
|
||||||
|
ConsoleColor.DarkCyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatAverageWindow(
|
||||||
|
TimeSpan now,
|
||||||
|
long hashes,
|
||||||
|
List<(TimeSpan Time, long Hashes)> history,
|
||||||
|
TimeSpan startTime,
|
||||||
|
TimeSpan window)
|
||||||
|
{
|
||||||
|
if(now - startTime < window)
|
||||||
|
return "warming up";
|
||||||
|
|
||||||
|
var cutoff = now - window;
|
||||||
|
(TimeSpan Time, long Hashes)? sample = null;
|
||||||
|
|
||||||
|
foreach(var item in history)
|
||||||
|
{
|
||||||
|
if(item.Time <= cutoff)
|
||||||
|
sample = item;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sample == null)
|
||||||
|
return "warming up";
|
||||||
|
|
||||||
|
var elapsed = (now - sample.Value.Time).TotalSeconds;
|
||||||
|
|
||||||
|
if(elapsed <= 0)
|
||||||
|
return "warming up";
|
||||||
|
|
||||||
|
var deltaHashes = hashes - sample.Value.Hashes;
|
||||||
|
var rate = deltaHashes / elapsed;
|
||||||
|
|
||||||
|
return FormatHashrate(rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TrimAverageHistory(
|
||||||
|
TimeSpan now,
|
||||||
|
List<(TimeSpan Time, long Hashes)> history)
|
||||||
|
{
|
||||||
|
var keepAfter = now - TimeSpan.FromMinutes(62);
|
||||||
|
|
||||||
|
while(history.Count > 2 &&
|
||||||
|
history[1].Time < keepAfter)
|
||||||
|
{
|
||||||
|
history.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatHashrate(double value)
|
private static string FormatHashrate(double value)
|
||||||
{
|
{
|
||||||
if(value >= 1_000_000)
|
if(value >= 1_000_000)
|
||||||
|
|
@ -956,7 +1291,7 @@ internal static class Program
|
||||||
|
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("Vexta CPU Miner 0.1.1");
|
Console.WriteLine("Vexta CPU Miner 0.1.2");
|
||||||
|
|
||||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||||
Console.WriteLine("Copyright (c) 2026 Vexta Project");
|
Console.WriteLine("Copyright (c) 2026 Vexta Project");
|
||||||
|
|
@ -996,7 +1331,7 @@ internal static class Program
|
||||||
Console.WriteLine(" -u Vexta address / worker name");
|
Console.WriteLine(" -u Vexta address / worker name");
|
||||||
Console.WriteLine(" -p Password (default: x)");
|
Console.WriteLine(" -p Password (default: x)");
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
" -t CPU threads (default: logical CPU count)");
|
" -t CPU threads (default: auto-detect physical cores)");
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("Ctrl+C stops the miner cleanly.");
|
Console.WriteLine("Ctrl+C stops the miner cleanly.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -20,8 +20,11 @@ Prebuilt binaries are available for:
|
||||||
- Vexta RandomX mining
|
- Vexta RandomX mining
|
||||||
- RandomX full-memory mode
|
- RandomX full-memory mode
|
||||||
- Windows x64 and Linux x64 support
|
- Windows x64 and Linux x64 support
|
||||||
- Configurable CPU thread count
|
- Automatic CPU thread selection based on physical cores
|
||||||
|
- Manual CPU thread override with `-t`
|
||||||
|
- Startup diagnostics for CPU, cores, AES, Huge Pages, and RandomX library
|
||||||
- Local hashrate display
|
- Local hashrate display
|
||||||
|
- 5 / 15 / 60 minute average hashrate
|
||||||
- Accepted / rejected share statistics
|
- Accepted / rejected share statistics
|
||||||
- Automatic RandomX seed changes
|
- Automatic RandomX seed changes
|
||||||
- Daemon-confirmed `BLOCK FOUND` notifications when supported by the pool
|
- Daemon-confirmed `BLOCK FOUND` notifications when supported by the pool
|
||||||
|
|
@ -59,7 +62,7 @@ Example:
|
||||||
| `-o` | Stratum pool address |
|
| `-o` | Stratum pool address |
|
||||||
| `-u` | Vexta wallet address, optionally followed by `.worker` |
|
| `-u` | Vexta wallet address, optionally followed by `.worker` |
|
||||||
| `-p` | Pool password, normally `x` |
|
| `-p` | Pool password, normally `x` |
|
||||||
| `-t` | Number of CPU mining threads |
|
| `-t` | Number of CPU mining threads (optional; auto-detects physical cores when omitted) |
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|
@ -69,6 +72,11 @@ Example:
|
||||||
|
|
||||||
RandomX full-memory mode is enabled.
|
RandomX full-memory mode is enabled.
|
||||||
|
|
||||||
|
On startup, the miner reports detected CPU information, physical and logical CPU counts,
|
||||||
|
AES support, Huge Pages status, RandomX library status, and the selected mining thread count.
|
||||||
|
|
||||||
|
If `-t` is omitted, the miner automatically uses the detected physical core count.
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -9,6 +10,51 @@ namespace Vexta.CpuMiner;
|
||||||
|
|
||||||
public static unsafe class VextaRandomX
|
public static unsafe class VextaRandomX
|
||||||
{
|
{
|
||||||
|
private static IntPtr nativeLibraryHandle = IntPtr.Zero;
|
||||||
|
|
||||||
|
public static string? NativeLibraryPath { get; private set; }
|
||||||
|
|
||||||
|
public static bool NativeLibraryLoaded => nativeLibraryHandle != IntPtr.Zero;
|
||||||
|
|
||||||
|
static VextaRandomX()
|
||||||
|
{
|
||||||
|
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
|
var libraryPath = Path.Combine(AppContext.BaseDirectory, "librandomx.so");
|
||||||
|
|
||||||
|
if(!File.Exists(libraryPath))
|
||||||
|
throw new DllNotFoundException(
|
||||||
|
$"RandomX library was not found at '{libraryPath}'.");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nativeLibraryHandle = NativeLibrary.Load(libraryPath);
|
||||||
|
NativeLibraryPath = libraryPath;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
throw new DllNotFoundException(
|
||||||
|
$"Unable to load RandomX library from '{libraryPath}': {ex.Message}",
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeLibrary.SetDllImportResolver(
|
||||||
|
typeof(VextaRandomX).Assembly,
|
||||||
|
(libraryName, assembly, searchPath) =>
|
||||||
|
{
|
||||||
|
if(string.Equals(
|
||||||
|
libraryName,
|
||||||
|
"librandomx",
|
||||||
|
StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return nativeLibraryHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IntPtr.Zero;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum RandomXFlags
|
public enum RandomXFlags
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue