09.09.25 SAPU //--XBTGPUARC-- //--Bitcoin Gold-- //--Zhash_144_5-- //--Equihash-- over //--Vector-- Calculations for //--Intel ARC Alchemist DG2 GPU--
//--Projekt: XBTGPUARC Miner-- //--Sprache: C++17 + OpenCL-- //--Ziel: Equihash 144,5 Mining auf Intel ARC GPUs--
//--kernels-- //-Zeilen um 777 Beachten!--
//-00--zhash.cl-Exclude-(Wir bauen ausschließlich um diesen einen Kernel herum!)--
//--XBTGPUARC_Dateien 0-13 sortiert A-Z-- //--1--globals.cpp-- //--2--globals.hpp-- //--3--main.cpp-- //--0--Makefile-- //--4--miner_loop.cpp-- //--5--miner_loop.hpp-- //--6--mining_job.hpp-- //--7--notify_parser.hpp-- //--8--opencl_utils_devices.cpp-- //--9--opencl_utils.cpp-- //--10--opencl_utils.hpp-- //--11--runs.sh-- //--12--stratum_notify_listener.cpp-- //--13.--stratum_notify_listener.hpp-- //--OpenCL-- //--C++17-- //--ARC INTEL DG2--
-------------------------------------> -------------------------------------> //--Inhalt Dateien A-Z-- -------------------------------------> -------------------------------------------------------------------------------------> //--1--globals.cpp-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
include "globals.hpp"
include "miner_loop.hpp"
//--Globale Variablen definieren--
bool abort_mining = false; bool socket_valid = false;
int next_request_id = 1; std::string current_job_id = ""; std::string worker_name = "";
std::array
//--Funktion implementieren--
void stop_mining() { abort_mining = true; }
-------------------------------------------------------------------------------------> //--2--globals.hpp-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
pragma once
include
include
include
include
define INPUT_SIZE 512
define HASH_SIZE 32
define NONCES_PER_THREAD 1
define BUCKET_COUNT 32
define HASH_ROUNDS_OUTPUT_SIZE 32
//--Hier werden die Ressourcen der Grafikkarte im Detail eingeteilt.
struct GpuResources { cl_context context = nullptr; cl_command_queue queue = nullptr; cl_program program = nullptr; cl_kernel kernel = nullptr; cl_device_id device = nullptr; cl_mem input_buffer = nullptr; cl_mem output_buffer = nullptr; cl_mem output_hashes_buffer = nullptr; cl_mem pool_target_buffer = nullptr; };
//--Externe Werte mit eingetragen.--
extern int next_request_id;
extern std::string current_job_id;
extern std::string worker_name;
extern bool abort_mining;
extern bool socket_valid;
extern std::array
-------------------------------------------------------------------------------------> //--3--main.cpp-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
include "globals.hpp"
include "miner_loop.hpp"
include "mining_job.hpp"
include "notify_parser.hpp"
include "opencl_utils.hpp"
include "stratum_notify_listener.hpp"
include
include
include
include
include
include
include
//--Alle OpenCL-Geräte auf dem Computer auflisten--
void list_opencl_devices() { cl_uint num_platforms = 0; cl_int err = clGetPlatformIDs(0, nullptr, &num_platforms); if (err != CL_SUCCESS) { std::cerr << "❌ Fehler bei clGetPlatformIDs: " << err << "\n"; return; }
std::vector
std::cout << "🌍 Gefundene OpenCL-Plattformen: " << num_platforms << "\n";
for (cl_uint i = 0; i < num_platforms; ++i) { char name[128], vendor[128], version[128]; clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, sizeof(name), name, nullptr); clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, sizeof(vendor), vendor, nullptr); clGetPlatformInfo(platforms[i], CL_PLATFORM_VERSION, sizeof(version), version, nullptr);
std::cout << "\n[Plattform " << i << "]\n";
std::cout << " Name: " << name << "\n";
std::cout << " Vendor: " << vendor << "\n";
std::cout << " Version: " << version << "\n";
cl_uint num_devices = 0;
err = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, nullptr,
&num_devices);
if (err != CL_SUCCESS || num_devices == 0) {
std::cout << " ⚠️ Keine Geräte gefunden.\n";
continue;
}
std::vector devices(num_devices);
clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, num_devices,
devices.data(), nullptr);
for (cl_uint j = 0; j < num_devices; ++j) {
char devname[128];
clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof(devname), devname,
nullptr);
std::cout << " [Device " << j << "] " << devname << "\n";
}
} }
int main(int argc, char **argv) {
//--Default-Werte--
int platform_index = 0; int device_index = 0; int intensity = 256; std::string algo = "zhash_144_5"; std::string wallet = "Gb4V4a9Jk3p8aH6jkW3Aq3sq8rQCuJQ6S8"; std::string worker = "A730m"; std::string password = "x"; std::string pool_host = "solo-btg.2miners.com"; int pool_port = 4040;
//--🧾 Argumente parsen--
for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if (arg == "--platform" && i + 1 < argc) platform_index = std::atoi(argv[++i]); else if (arg == "--device" && i + 1 < argc) device_index = std::atoi(argv[++i]); else if (arg == "--intensity" && i + 1 < argc) intensity = std::atoi(argv[++i]); else if (arg == "--algo" && i + 1 < argc) algo = argv[++i]; else if (arg == "--wallet" && i + 1 < argc) wallet = argv[++i]; else if (arg == "--worker" && i + 1 < argc) worker = argv[++i]; else if (arg == "--password" && i + 1 < argc) password = argv[++i]; else if (arg == "--pool" && i + 1 < argc) pool_host = argv[++i]; else if (arg == "--port" && i + 1 < argc) pool_port = std::atoi(argv[++i]); else if (arg == "--help") { std::cout << "Usage: ./xbtgpuarc [options]\n" << "Options:\n" << " --platform N OpenCL Plattform-Index (default 0)\n" << " --device N OpenCL Geräte-Index (default 0)\n" << " --intensity N Threads pro Gerät (default 256)\n" << " --algo NAME Kernel/Algo-Name (default zhash_144_5)\n" << " --wallet ADDR Wallet-Adresse\n" << " --worker NAME Worker-Name\n" << " --password PASS Passwort für Pool (default 'x')\n" << " --pool HOST Pool-Adresse (default 2miners)\n" << " --port PORT Port (default 4040)\n"; return 0; } }
std::cout << "🚀 Starte XBTGPUARC mit Algo: " << algo << "\n"; std::cout << "👤 Worker: " << wallet << "." << worker << "\n"; std::cout << "🎛️ Platform: " << platform_index << " | Device: " << device_index << " | Intensity: " << intensity << "\n"; std::cout << "🌐 Pool: " << pool_host << ":" << pool_port << "\n";
list_opencl_devices();
//--Initialisiere OpenCL--
GpuResources resources; init_opencl("kernels/zhash.cl",algo, platform_index, device_index, intensity, resources);
//--Starte Stratum-Listener + Mining-Thread--
run_stratum_listener(pool_host, pool_port, wallet, worker, password, intensity, resources);
cleanup_opencl(resources); return 0; }
-------------------------------------------------------------------------------------> //--0--Makefile-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
Hier startet man den Bauvorgang für das Miningprogramm auf seinem Computer um es Einsatzbereit zu machen.--
CXXFLAGS := -std=c++17 -Wall -O2 -DCL_TARGET_OPENCL_VERSION=300 -MMD -MP LDFLAGS := -lOpenCL -lboost_system -lboost_json -lpthread
Quellcode-Dateien--
SRC := main.cpp \ miner_loop.cpp \ opencl_utils.cpp \ stratum_notify_listener.cpp \ globals.cpp
OBJ := $(SRC:.cpp=.o) DEPS := $(OBJ:.o=.d) OUT := xbtgpuarc
//--Standard-Ziel/Target--
all: $(OUT)
Bau des GPU-Miners--
$(OUT): $(OBJ) $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
Generisches Compile-Ziel--
%.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@
Säubern--
clean: rm -f $(OUT) $(CPU_OUT) .o .d
-include $(DEPS)
-------------------------------------------------------------------------------------> //--4--miner_loop.cpp-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
include "miner_loop.hpp"
include "mining_job.hpp"
include "opencl_utils.hpp"
include
include //--Eventuell Austragbar weil fester Algo--
include
include //--Atomic Nutzen Ja Nein Vielleicht erstmal Ja--
include //--Für std::isxdigit--
include //--Für Uhrzeit der Netzwekoperation--
include
include
include
include
include
include
include
include //--Für std::random_device und std::mt19937--
include
include
include //--FÜr Intel ARC GPUs DG2 Alchmemist--
//--Externe Status-Variablen-- //--Diese Variablen sind nicht in dieser Datei definiert, sondern werden von außen bereitgestellt.-- //--Sie dienen dazu, den Abbruch des Minings oder den Status der Socket-Verbindung zu signalisieren.-- //--Es sind einfache bool-Werte, die direkt gelesen werden.--
extern std::atomic
//--Globale OpenCL-Objekte--
cl_context context = nullptr; cl_command_queue queue = nullptr; cl_kernel kernel = nullptr; cl_program program = nullptr; cl_device_id device = nullptr;
//--🧱 Erstellt den Eingabepuffer aus dem MiningJob--
namespace {
//--Prüft, ob ein Zeichen eine Hexadezimalziffer ist--
//--Eine Hexadezimalziffer ist 0-9 oder A-F (Groß- oder Kleinbuchstaben).--
inline bool is_hex_char(unsigned char c) {
return std::isxdigit(c) != 0;
}
//--Prüft, ob ein String ein gültiger Hexadezimal-String ist--
//--Ein String ist gültig, wenn er leer ist oder nur Hexadezimalziffern enthält--
//--und eine gerade Länge hat (da ein Byte aus zwei Hex-Ziffern besteht).--
//--Optional kann ein "0x"-Präfix erlaubt sein.--
bool is_valid_hex(const std::string& s, bool allow_0x_prefix = true) {
if (s.empty()) return false;
std::string clean = s;
if (allow_0x_prefix && s.size() >= 2 &&
s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
clean = s.substr(2); //--Präfix entfernen, wenn erlaubt--
}
if (clean.empty() || (clean.size() % 2) != 0) return false; //--Muss eine gerade Länge haben--
for (unsigned char c : clean) {
if (!is_hex_char(c)) return false; //--Alle Zeichen müssen Hex-Ziffern sein--
}
return true;
}
//--Entfernt ein optionales "0x"-Präfix von einem Hex-String--
//--Wenn der String mit "0x" oder "0X" beginnt, wird dieser Teil entfernt.--
std::string remove_0x_prefix(const std::string& s) {
if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
return s.substr(2);
}
return s;
}
//--Konvertiert einen Hex-String in Bytes und hängt sie an einen Puffer an--
//--Diese Funktion nimmt einen Hex-String und wandelt jedes Paar von Hex-Ziffern--
//--in ein einzelnes Byte um, das dann einem cl_uchar-Vektor hinzugefügt wird.--
//--Sie beinhaltet eine verbesserte Fehlerbehandlung für ungültige Eingaben.--
void append_hex_to_buffer(const std::string& hex, std::vector& buffer,
const std::string& field_name = "") {
if (hex.empty()) return;
std::string clean_hex = remove_0x_prefix(hex);
if (!is_valid_hex(clean_hex, false)) { //--Prüfen ohne Präfix--
throw std::invalid_argument("Ungültiger Hex-String für Feld '" +
field_name + "': " + hex);
}
buffer.reserve(buffer.size() + clean_hex.size() / 2); //--Speicher im Voraus reservieren--
for (size_t i = 0; i < clean_hex.size(); i += 2) {
try {
unsigned long byte_val = std::stoul(clean_hex.substr(i, 2), nullptr, 16);
if (byte_val > 0xFF) { //--Ein Byte ist max. 255 (0xFF)--
throw std::out_of_range("Byte-Wert außerhalb des Bereichs");
}
buffer.push_back(static_cast(byte_val));
} catch (const std::exception& e) {
throw std::invalid_argument("Konvertierungsfehler in Feld '" +
field_name + "' bei Position " +
std::to_string(i) + ": " + e.what());
}
}
}
//--Erstellt den Eingabepuffer für den OpenCL-Kernel aus einem MiningJob--
//--Diese Funktion sammelt alle relevanten Hex-Strings aus dem MiningJob-Objekt--
//--(Version, Prevhash, Ntime, Coinb1, Extranonce1, Extranonce2, Coinb2 und Merkle-Branch)--
//--und konvertiert sie in einen Vektor von Bytes, der als Eingabe für die GPU dient.--
void build_input_from_job(const MiningJob& job, std::vector& input_buffer) {
input_buffer.clear();
try {
append_hex_to_buffer(job.version, input_buffer, "version");
append_hex_to_buffer(job.prevhash, input_buffer, "prevhash");
append_hex_to_buffer(job.ntime, input_buffer, "ntime");
append_hex_to_buffer(job.coinb1, input_buffer, "coinb1");
append_hex_to_buffer(job.extranonce1, input_buffer, "extranonce1");
append_hex_to_buffer(job.extranonce2, input_buffer, "extranonce2");
append_hex_to_buffer(job.coinb2, input_buffer, "coinb2");
for (size_t i = 0; i < job.merkle_branch.size(); ++i) {
append_hex_to_buffer(job.merkle_branch[i], input_buffer,
"merkle_branch[" + std::to_string(i) + "]");
}
} catch (const std::exception& e) {
input_buffer.clear(); //--Puffer im Fehlerfall leeren--
throw; //--Fehler weitergeben--
}
}
//--Sichere Konvertierung eines Hex-Strings in einen 32-Bit-Integer (uint32_t)--
//--Diese Funktion wandelt einen Hex-String in eine vorzeichenlose 32-Bit-Ganzzahl um.--
//--Sie prüft auf Gültigkeit des Hex-Strings und stellt sicher, dass der Wert nicht--
//--über den maximalen Wert von uint32_t hinausgeht, um Überläufe zu vermeiden.--
std::optional safe_stoul_hex_u32(const std::string& hex) {
std::string clean_hex = remove_0x_prefix(hex);
if (!is_valid_hex(clean_hex, false)) return std::nullopt; //--Prüfen ohne Präfix--
try {
size_t idx = 0;
unsigned long v = std::stoul(clean_hex, &idx, 16);
if (idx != clean_hex.size()) return std::nullopt; //--Nicht alle Zeichen gelesen--
if (v > std::numeric_limits::max()) return std::nullopt; //--Wert zu groß--
return static_cast(v);
} catch (...) {
return std::nullopt; //--Konvertierungsfehler--
}
}
//--Verbesserte OpenCL-Fehlerbehandlung-
//--Diese Funktion prüft den Rückgabewert eines OpenCL-Aufrufs. Wenn ein Fehler auftritt,--
//--wird eine Fehlermeldung ausgegeben und optional das Build-Log des Kernels,--
//--falls die GpuResources verfügbar sind und ein Fehler im Build-Prozess vorlag.--
bool check_cl(cl_int err, const char* where, const GpuResources* resources = nullptr) {
if (err == CL_SUCCESS) return true; //--Alles in Ordnung--
std::cerr << "❌ OpenCL-Fehler (" << err << ") bei: " << where << "\n";
//--Build-Log ausgeben, falls Programm und Gerät bekannt sind--
if (resources && resources->program && resources->device) {
size_t log_size = 0;
clGetProgramBuildInfo(resources->program, resources->device,
CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
if (log_size > 0) { //--Wenn ein Log vorhanden ist--
std::vector build_log(log_size + 1); //--Dynamisch Puffer allozieren--
clGetProgramBuildInfo(resources->program, resources->device,
CL_PROGRAM_BUILD_LOG, log_size, build_log.data(), nullptr);
std::cerr << "Build-Log:\n" << build_log.data() << "\n";
}
}
return false; //--Fehler aufgetreten--
}