//--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--
//-00--zhash.cl-Exclude-(We build around the Kernel!)--
//--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-- no changes in Codelanguage here without extra attention. All Data are made before Training. Program you see work in early state! Do not change significant Options or Code before EXTRA FAT WARNING! Questions about everything recommend and welcome. Lets work together!
//--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
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; };
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 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--
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
Optional: CPU-Miner
CPU_SRC := cpu_miner.cpp globals.cpp CPU_OBJ := $(CPU_SRC:.cpp=.o) CPU_OUT := cpu_miner CXXFLAGS := -std=c++17 -Wall -O3 -march=native -DCL_TARGET_OPENCL_VERSION=300 LDFLAGS := -lOpenCL -lboost_system -lboost_json -lpthread
Standard-Target
all: $(OUT)
Build des GPU-Miners
$(OUT): $(OBJ) $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
Optional: CPU-Miner separat bauen
$(CPU_OUT): $(CPU_OBJ) $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
Generisches Compile-Ziel
%.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@
Clean
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
include
include
include
include
include
include
include //--Für std::random_device und std::mt19937--
include
include
//--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 bool abort_mining; extern bool socket_valid;
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--
}
//--RAII-Wrapper für OpenCL-Speicherobjekte (cl_mem)-
//--Dieser Wrapper sorgt dafür, dass OpenCL-Speicherobjekte automatisch freigegeben werden,-
//--wenn sie nicht mehr benötigt werden (z. B. wenn der Wrapper den Gültigkeitsbereich verlässt).-
//--Dies verhindert Speicherlecks und vereinfacht die Fehlerbehandlung.--
struct CLMemWrapper {