create account

XBTGPUARC Hauptprogramm in Deutsch erklährt und ausgeführt. by alucian

View this thread on: hive.blogpeakd.comecency.com
· @alucian ·
$0.59
XBTGPUARC Hauptprogramm in Deutsch erklährt und ausgeführt.
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<uint8_t, 32> current_target = {};

//--Funktion implementieren--

void stop_mining() { abort_mining = true; }

------------------------------------------------------------------------------------->
//--2--globals.hpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#pragma once

#include <CL/cl.h>
#include <array>
#include <cstdint>
#include <string>

#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<uint8_t, 32> current_target;

------------------------------------------------------------------------------------->
//--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 <CL/cl.h>
#include <array>
#include <cstdlib>
#include <iostream>
#include <random>
#include <string>
#include <vector>

//--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<cl_platform_id> platforms(num_platforms);
  clGetPlatformIDs(num_platforms, platforms.data(), nullptr);

  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<cl_device_id> 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 <CL/cl.h>
#include <algorithm> //--Eventuell Austragbar weil fester Algo--
#include <array>
#include <atomic> //--Atomic Nutzen Ja Nein Vielleicht erstmal Ja--
#include <cctype> //--Für std::isxdigit--
#include <chrono> //--Für Uhrzeit der Netzwekoperation--
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <optional>
#include <random> //--Für std::random_device und std::mt19937--
#include <string>
#include <thread>
#include <vector> //--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<bool> abort_mining;
extern std::atomic<bool> socket_valid;
extern std::atomic<bool> job_wurde_übernommen;

//--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<cl_uchar>& 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<cl_uchar>(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<cl_uchar>& 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<uint32_t> 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<uint32_t>::max()) return std::nullopt; //--Wert zu groß--

                                      return static_cast<uint32_t>(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<char> 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 {
                                  cl_mem mem = nullptr; // Das OpenCL-Speicherobjekt

                                  explicit CLMemWrapper(cl_mem mem_obj = nullptr) : mem(mem_obj) {}

                                  //--Destruktor: Gibt das Speicherobjekt frei, wenn der Wrapper zerstört wird--

                                  ~CLMemWrapper() { if (mem) clReleaseMemObject(mem); }

                                  //--Kopierkonstruktor und Zuweisungsoperator sind gelöscht (nicht kopierbar)--

                                  CLMemWrapper(const CLMemWrapper&) = delete;
                                  CLMemWrapper& operator=(const CLMemWrapper&) = delete;

                                  //--Move-Konstruktor: Ermöglicht das Verschieben von Besitzrechten--

                                  CLMemWrapper(CLMemWrapper&& other) noexcept : mem(other.mem) {
                                      other.mem = nullptr; // Quelle leeren
                                  }

                                  //--Move-Zuweisungsoperator: Ermöglicht das Verschieben von Besitzrechten--

                                  CLMemWrapper& operator=(CLMemWrapper&& other) noexcept {
                                      if (this != &other) { //--Selbstzuweisung verhindern--
                                          if (mem) clReleaseMemObject(mem); //--Eigenes Objekt freigeben--
                                          mem = other.mem;
                                          other.mem = nullptr; //--Quelle leeren--
                                      }
                                      return *this;
                                  }

                                  //--Konvertierungsoperator: Ermöglicht die implizite Umwandlung in cl_mem--

                                  operator cl_mem() const { return mem; }

                                  //--Expliziter bool-Operator: Prüft, ob ein gültiges Speicherobjekt vorhanden ist--

                                  explicit operator bool() const { return mem != nullptr; }
                              };

                 //--Der Miner-Loop-
                 //--Dies ist die Hauptschleife des Miners. Sie wiederholt die folgenden Schritte,--
                 //--um nach gültigen Lösungen zu suchen:--
                 //--1. Hole den aktuellen Mining-Job.--
                 //--2. Erstelle eine Start-Nonce für diese Batch-Verarbeitung.--
                 //--3. Aktualisiere die Daten auf der Grafikkarte (GPU), falls sich der Job geändert hat.--
                 //--4. Setze die Argumente für den OpenCL-Kernel.--
                 //--5. Starte den Kernel (das ist das eigentliche Rechenprogramm auf der GPU).--
                 //--6. Warte, bis der Kernel fertig ist.--
                 //--7. Lies die Ergebnisse (die gefundenen Lösungen) von der GPU zurück.--
                 //--8. Überprüfe die gefundenen Lösungen.--

                 void miner_loop(GpuResources& resources,
                                 const std::function<MiningJob()> get_current_job,
                                 const std::function<void(uint32_t, const std::array<uint8_t, 32>&,
                                 const MiningJob&)> on_valid_share) {
                                 const GpuResources &resources, int intensity
) {
  //--Initialisierung des Zufallszahlengenerators--
  //--Ein guter Zufallszahlengenerator ist wichtig für die Nonce.--
  //--Ein guter Zufallszahlengenerator ist wichtig für die Nonce.--
  //--Ein guter Zufallszahlengenerator ist wichtig für die Nonce.--

                     std::random_device rd; //--Quelle für echte Zufallszahlen--
                     std::mt19937 rng(rd()); //--Mersenne Twister Engine--
                     std::uniform_int_distribution<uint32_t> dist; //--Für 32-Bit Zufallszahlen--

                     //--SYCL-Beispiel für ulong8-Vergleiche--
                     //--Holen des initialen Mining-Jobs--
                     //--Der erste Job, mit dem der Miner startet.--

                     MiningJob current_job = get_current_job();
                     std::string current_job_id = current_job.job_id;

                     //--Work-Size berechnen--
                     //--Dies sind die Größen, die der GPU sagen, wie viele Arbeitseinheiten--
                     //--sie gleichzeitig verarbeiten soll. Hardcoded für einfache Kontrolle.--

                      sycl::vec<ulong, 8> nonce = ...; //--512-bit Nonce-Berechnung--
                      sycl::vec<ulong, 8> hash = blake2b(nonce); //--SIMD-optimierte Hashfunktion--
                     const size_t local_work_size = 64; //--Größe einer lokalen Arbeitsgruppe--
                     const size_t min_intensity = 1;    //--Mindestintensität, kann extern kommen--
                     const size_t batch_size = min_intensity * 4096ULL; //--Gesamtmenge der Nonces pro Batch--

                      //--Globale Work-Size ist ein Vielfaches der lokalen, um volle Gruppen zu gewährleisten--

 size_t global_work_size =
      ((batch_size + local_work_size - 1) / local_work_size) * local_work_size;

      //--Host-Puffer für Ergebnisse--
      //--Hier werden die Ergebnisse von der GPU zwischengespeichert, bevor sie verarbeitet werden.--

  //--2-- Target berechnen--

  auto clean_bits = sanitize_hex_string(job.nbits);
  auto maybe_bits = safe_stoul_hex(clean_bits);
  if (!maybe_bits)
    return;
  std::vector<uint8_t> target = bits_to_target(*maybe_bits);

  //--3-- Puffer vorbereiten--

  std::vector<cl_uchar> host_input_buffer;
  build_input_from_job(job, host_input_buffer);
  host_input_buffer.resize(512, 0);


                     //--Globale Work-Size ist ein Vielfaches der lokalen, um volle Gruppen zu gewährleisten--
                    size_t global_work_size =
                     const size_t global_work_size = ((batch_size + local_work_size - 1) / local_work_size) * local_work_size;

                     //--Host-Puffer für Ergebnisse--
                     //--Hier werden die Ergebnisse von der GPU zwischengespeichert, bevor sie verarbeitet werden.--

 std::vector<cl_uchar> output_buffer(32 * batch_size); //--Für die finalen Hashes (32 Bytes pro Hash)--
  std::vector<cl_uint> index_buffer(2 * batch_size, 0); //--Für die Indizes der gefundenen Paare (idxA, idxB)--

       //--4--OpenCL-Puffer für die GPU anlegen--
       //--Diese Puffer werden nur einmal am Anfang erstellt und dann immer wiederverwendet.--
       //--Das ist effizienter, als sie in jeder Schleife neu zu erstellen.--

        cl_int err = CL_SUCCESS; //--Für die Fehlerprüfung der OpenCL-Aufrufe--

        //--Eingabepuffer für die Job-Daten--

        CLMemWrapper cl_input(clCreateBuffer(resources.context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                     512, host_input_buffer.data(), &err);
        if (!check_cl(err, "clCreateBuffer(cl_input)", &resources)) return;

        //--Ausgabepuffer für die Hashes, die der Kernel erzeugt--

        CLMemWrapper cl_output = clCreateBuffer(resources.context, CL_MEM_WRITE_ONLY,
                                    output_buffer.size(), nullptr, &err);
        if (!check_cl(err, "clCreateBuffer(cl_output)", &resources)) return;

        //--Puffer für die Indizes der Hash-Paare--

        CLMemWrapper cl_indexes =
        clCreateBuffer(resources.context, CL_MEM_WRITE_ONLY,
                     index_buffer.size() * sizeof(cl_uint), nullptr, &err);
        if (!check_cl(err, "clCreateBuffer(cl_indexes)", &resources)) return;


        //--Puffer für die Anzahl der gefundenen Lösungen--</pre>

        CLMemWrapper cl_solution_count.mem = clCreateBuffer(
        resources.context, CL_MEM_READ_WRITE, sizeof(cl_uint), nullptr, &err);

        if (!check_cl(err, "clCreateBuffer(cl_solution_count)", &resources)) return;
        if (err != CL_SUCCESS) { /* Fehlerbehandlung */
  }

  //--5--Haupt-Mining-Schleife--
  //--Diese Schleife läuft, solange das Mining nicht abgebrochen werden soll--
  //--und die Socket-Verbindung gültig ist.--

    while (!abort_mining && socket_valid) { //--Keine .load() mehr, direkte bool-Abfrage--
    uint32_t start_nonce = batch_size;
    ;
    //--Job-Wechsel-Logik--
    //--Wir fragen nach dem neuesten Job. Wenn sich die Job-ID geändert hat,--
    //--dann aktualisieren wir unseren aktuellen Job.--

    MiningJob new_job = get_current_job();
    if (new_job.job_id != current_job_id) {
      std::cout << "🔄 Neuer Job empfangen: " << new_job.job_id << "\n";
      current_job = new_job;
      current_job_id = new_job.job_id; //--Job-ID aktualisieren--


      //--Bei Job-Wechsel müssen die Eingabepuffer für die GPU neu gebaut werden.--
      //--Die Puffer selbst werden NICHT neu erstellt, nur ihr Inhalt aktualisiert.--

    }

    //--Target berechnen--
    //--Der "Target"-Wert bestimmt, wie schwierig es ist, einen gültigen Hash zu finden.--
    //--Er wird aus dem "nbits" des aktuellen Jobs berechnet.--

    auto maybe_bits = safe_stoul_hex_u32(current_job.nbits);
    if (!maybe_bits) {
      std::cerr << "❌ Ungültige nbits: " << current_job.nbits << "\n";

      //--Ein kurzer Schlaf, um die CPU nicht zu überlasten, wenn Fehler auftreten--

      continue; //--Nächste Schleifeniteration versuchen--
    }
    std::vector<uint8_t> target = bits_to_target(*maybe_bits);

    //--Eingabepuffer für den Kernel vorbereiten--
    //--Die Job-Daten werden in ein Format gebracht, das die GPU verarbeiten kann.--

    std::vector<cl_uchar> host_input;
    try {
      build_input_from_job(current_job, host_input);
      host_input.resize(512, 0); //--Sicherstellen, dass der Puffer eine Mindestgröße hat--
    } catch (const std::exception& e) {
      std::cerr << "❌ Fehler beim Erstellen des Eingabepuffers: " << e.what() << "\n";
      continue;
    }

    //--Start-Nonce für diese Arbeitsgruppe--
    //--Eine zufällige Start-Nonce, um verschiedene Teile des Nonce-Raums zu durchsuchen.--

     const uint32_t start_nonce = dist(rng);

    //--Solution-Count auf Null zurücksetzen--
    //--Vor jedem Kernel-Lauf setzen wir den Zähler für die gefundenen Lösungen zurück.--

   const cl_uint zero = 0;
    if (!check_cl(clEnqueueWriteBuffer(resources.queue, cl_solution_count.mem, CL_TRUE, 0,
                         sizeof(cl_uint), &zero, 0, nullptr, nullptr);
                        "clEnqueueWriteBuffer(solution_count=0)", &resources)) {
                        continue;
    }

    //--Daten zur GPU schicken (Inhalt der Puffer aktualisieren)--
    //--Hier werden die vorbereiteten Job-Daten auf die GPU kopiert.--
    //--Die Pufferobjekte bleiben dieselben, nur die Daten ändern sich.--

    if (!check_cl(clEnqueueWriteBuffer(resources.queue, cl_input.mem, CL_TRUE, 0,
      host_input.size(), host_input.data(),
                                       0, nullptr, nullptr),
                                        "clEnqueueWriteBuffer(input_data)", &resources)) {
                                        continue;
                }

    //--Vor der Kernel-Ausführung--
    //--Kernel-Argumente setzen (dem Kernel sagen, welche Puffer er nutzen soll)--
    //--Die Argumente werden jedes Mal neu gesetzt, da sich die Daten oder die Start-Nonce ändern können.--

    if (!check_cl(clSetKernelArg(resources.kernel, 0, sizeof(cl_mem), &cl_input.mem),
      "clSetKernelArg(0, cl_input)", &resources)) continue;
    if (!check_cl(clSetKernelArg(resources.kernel, 1, sizeof(cl_mem), &cl_output.mem),
      "clSetKernelArg(1, cl_output)", &resources)) continue;
    if (!check_cl(clSetKernelArg(resources.kernel, 2, sizeof(cl_mem), &cl_indexes.mem),
      "clSetKernelArg(2, cl_indexes)", &resources)) continue;
    if (!check_cl(clSetKernelArg(resources.kernel, 3, sizeof(cl_mem), &cl_solution_count.mem),
      "clSetKernelArg(3, cl_solution_count)", &resources)) continue;
    if (!check_cl(clSetKernelArg(resources.kernel, 4, sizeof(uint32_t), &start_nonce),
      "clSetKernelArg(4, start_nonce)", &resources)) continue;

    std::cout << "Starting mining loop with:\n";
    std::cout << "  Job ID: " << job.job_id << "\n";
    std::cout << "  PrevHash: " << job.prevhash << "\n";
    std::cout << "  Target: " << job.nbits << "\n";
    std::cout << "  Intensity: " << intensity << "\n";

    //--Den Kernel auf der GPU ausführen!!!--
    //--Die eigentliche Rechenarbeit beginnt.--

    cl_event evt = nullptr; //--Ereignisobjekt für die Kernel-Ausführung--

    err = clEnqueueNDRangeKernel(resources.queue, resources.kernel, 1, nullptr,
                                 &global_work_size, &local_work_size, 0,
                                 nullptr, &event);
    if (!check_cl(err, "clEnqueueNDRangeKernel", &resources)) {
      if (evt) clReleaseEvent(evt); //--Ereignis freigeben--
      continue;
    }
    clWaitForEvents(1, &event); //--Warten, bis der Kernel fertig ist--
    clReleaseEvent(evt);      //--Ereignis freigeben--

    //--Lösungen verarbeiten--
    //--Ergebnisse von der GPU zurücklesen--
    //--Die gefundenen Hashes, Indizes und die Lösungsanzahl werden von der GPU geholt.--

     if (!check_cl(clEnqueueReadBuffer(resources.queue, cl_output.mem, CL_TRUE, 0,
                        output_buffer.size(), output_buffer.data(), 0, nullptr, nullptr);
                         "clEnqueueReadBuffer(output)", &resources)) continue;

     if (!check_cl(clEnqueueReadBuffer(resources.queue, cl_indexes.mem, CL_TRUE, 0,
                        index_buffer.size() * sizeof(cl_uint),
                        index_buffer.data(), 0, nullptr, nullptr);
                        "clEnqueueReadBuffer(indexes)", &resources)) continue;

                        cl_uint solution_count = 0;
                        if (!check_cl(clEnqueueReadBuffer(resources.queue, cl_solution_count.mem, CL_TRUE, 0,
                        sizeof(cl_uint), &solution_count, 0, nullptr, nullptr),
                        "clEnqueueReadBuffer(solution_count)", &resources)) continue;

    //--Gefundene Lösungen verarbeiten (PLATZHALTER)--
    //--HIER kommt deine ECHTE PoW-Validierungslogik rein!--
    //--Aktuell wird ein Platzhalter-XOR-Check durchgeführt.--

    for (size_t i = 0; i < batch_size; ++i) {
      const uint32_t idxA = index_buffer[i * 2];
      const uint32_t idxB = index_buffer[i * 2 + 1];

      if (idxA == 0 && idxB == 0)
        continue;

      //--Gültigkeitsprüfung der Indizes--

      if (idxA >= batch_size || idxB >= batch_size) //--Sollte nicht passieren, aber zur Sicherheit!--
        continue;

      std::array<uint8_t, 32> final_hash; //--32 Bytes für den Hash--
      for (int j = 0; j < 32; ++j) {
        final_hash[j] =
            output_buffer[idxA * 32 + j] ^ output_buffer[idxB * 32 + j];
      }
      const size_t offsetA = static_cast<size_t>(idxA) * 32 + j;
      const size_t offsetB = static_cast<size_t>(idxB) * 32 + j;
      if (is_valid_hash(final_hash, target)) {
        on_valid_share(start_nonce + idxA, final_hash, job);
      }
    }
  }

  //--Aufräumen--

  clReleaseMemObject(cl_input);
  clReleaseMemObject(cl_output);
  clReleaseMemObject(cl_indexes);
  clReleaseMemObject(cl_solution_count);
  clReleaseKernel(resources.kernel);
  clReleaseProgram(resources.program);
  clReleaseCommandQueue(resources.queue);
  clReleaseContext(resources.context);
}

//--Aufräumen (nicht explizit nötig wegen RAII)--
//--Die CLMemWrapper-Objekte (cl_input, cl_output, etc.) geben ihren--
//--Speicher automatisch frei, wenn die Funktion endet.--


------------------------------------------------------------------------------------->
//--5--miner_loop.hpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#pragma once

#include "mining_job.hpp"
#include "opencl_utils.hpp"
#include "optional"
#include <array>
#include <functional>
#include <string>

//--Externe Globals--
//--Mining-Steuerung--

void stop_mining();
void miner_loop(
const MiningJob &job,
const std::function<void(uint32_t, const std::array<uint8_t, 32> &,
const MiningJob &)> &on_valid_share,
 const GpuResources &resources, int intensity);

//--Hex-Helfer--

std::string sanitize_hex_string(const std::string &input);
std::optional<uint32_t> safe_stoul_hex(const std::string &hex_str);

------------------------------------------------------------------------------------->
//--6--mining_job.hpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#pragma once

#include <array>
#include <cstdint>
#include <string>
#include <vector>

//--Enthält einen vollständigen MiningJob basierend auf einem Benachrichtigungs Ereignis--

struct MiningJob {
  std::string job_id;
  std::string prevhash;
  std::string coinb1;
  std::string coinb2;
  std::vector<std::string> merkle_branch;
  std::string version;
  std::string nbits;
  std::string ntime;
  std::string extranonce1;
  std::string extranonce2;
  std::string bits;
};

//--Vergleich: Hash < Target--

inline bool is_valid_hash(const std::array<uint8_t, 32> &hash,
                          const std::vector<uint8_t> &target) {
  for (size_t i = 0; i < 32; ++i) {
    if (hash[i] < target[i])
      return true;
    if (hash[i] > target[i])
      return false;
  }
  return true;
}

//--Wandelt Compact-Format aus "bits" (z. B. 0x1d00ffff) in 256-bit Target!--

inline std::vector<uint8_t> bits_to_target(uint32_t bits) {
  uint32_t exponent = bits >> 24;
  uint32_t mantissa = bits & 0x007fffff;

  std::vector<uint8_t> target(32, 0);

  if (exponent <= 3) {

    //--Mantisse nach rechts schieben--

    mantissa >>= 8 * (3 - exponent);
    target[31] = mantissa & 0xFF;
    target[30] = (mantissa >> 8) & 0xFF;
    target[29] = (mantissa >> 16) & 0xFF;
  } else if (exponent <= 32) {

    //--Platzierung der Mantisse ab dem richtigen Byte--

    int idx = 32 - exponent;
    target[idx] = (mantissa >> 16) & 0xFF;
    target[idx + 1] = (mantissa >> 8) & 0xFF;
    target[idx + 2] = mantissa & 0xFF;
  } else {

    //--Exponent außerhalb gültigem Rahmens--
    //-→Zurück für leeres Ziel (niemals gültig)--

    return std::vector<uint8_t>(32, 0xFF);
  }

  return target;
}

------------------------------------------------------------------------------------->
//--7--notify_parser.hpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
#pragma once

#include "mining_job.hpp"
#include <boost/json.hpp>
#include <iostream>
#include <optional>
#include <string>
#include <vector>

//--Diese Funktion parst eine JSON-Zeile vom Pool und wandelt sie in ein--
//-MiningJob-Objekt um.--

inline std::optional<MiningJob> parse_notify(const std::string &line) {
  using namespace boost::json;
  boost::system::error_code ec;
  value json_value = parse(line, ec);

  if (ec || !json_value.is_object()) {
    return std::nullopt; //--Keine gültige JSON-Nachricht--
  }

  const object &obj = json_value.as_object();

  //--Sicherstellen, dass es eine "mining.notify"-Nachricht ist--

  if (!obj.contains("method") ||
      value_to<std::string>(obj.at("method")) != "mining.notify") {
    return std::nullopt;
  }

  if (!obj.contains("params") || !obj.at("params").is_array()) {
    std::cerr << "❌ Fehler: 'mining.notify' hat keine gültigen Parameter.\n";
    return std::nullopt;
  }
  const array &params = obj.at("params").as_array();

  //--Die Parameter-Anzahl für BTG auf 2miners.com ist typischerweise 8 oder mehr--
  //--Das Programm wird am Ende auf Solo und Poolmining zur Auswahl aufgestockt, bis diese Zeilen Ersetzt wurden.--

  if (params.size() < 8) {
    std::cerr << "❌ Fehler: 'mining.notify' hat zu wenige Parameter ("
              << params.size() << "). Erwartet >= 8.\n";
    return std::nullopt;
  }

  MiningJob job;

  //--Parameterzuweisung LOG
  //--Stratum-Protokoll für solo-btg.2miners.com:--
  //--params[0]: job_id--
  //--params[1]: version--
  //--params[2]: prevhash--
  //--params[3]: coinb1--
  //--params[4]: coinb2--
  //--params[5]: nbits--
  //--params[6]: ntime--
  //--params[7]: clean_job (boolean)--

  //-WICHTIG: Dieser Pool sendet KEINEN separaten 'merkle_branch'.--
  //-Der Merkle-Root muss vom Miner selbst berechnet werden, indem--
  //-die Coinbase-Transaktion gehasht wird. Die 'merkle_branch'--
  //-Liste bleibt also absichtlich leer.--

  job.job_id = value_to<std::string>(params.at(0));
  job.version = value_to<std::string>(params.at(1));
  job.prevhash = value_to<std::string>(params.at(2));
  job.coinb1 = value_to<std::string>(params.at(3));
  job.coinb2 = value_to<std::string>(params.at(4));
  job.nbits = value_to<std::string>(params.at(5));
  job.ntime = value_to<std::string>(params.at(6));
  job.clean_job = params.at(7).as_bool();

  //--Die Merkle Branch Liste wird explizit geleert, da sie nicht vom Pool kommt.--

  job.merkle_branch.clear();
  std::cout << "🌿 Job korrekt geparst. Merkle Branch ist leer, wie vom Pool "
               "erwartet.\n";

  //--Alte Felder für Kompatibilität füllen--

  job.bits = job.nbits;
  job.extranonce1 = "";         //--Wird später vom Unterschreiber gesetzt--
  job.extranonce2 = "00000000"; //--Platzhalter--

  //--Debug-Ausgabe--


  std::cout << "🔍 Debug Notify: bits = '" << job.nbits << "', ntime = '"
            << job.ntime << "'\n";

  return job;
}

------------------------------------------------------------------------------------->
//--8--opencl_list_devices.cpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#include <CL/cl.h>
#include <iostream>
#include <string>
#include <vector>

void check_error(cl_int err, const std::string &msg) {
  if (err != CL_SUCCESS) {
    std::cerr << "❌ Fehler: " << msg << " (" << err << ")\n";
    exit(1);
  }
}

int main() {
  cl_uint num_platforms = 0;
  cl_int err = clGetPlatformIDs(0, nullptr, &num_platforms);
  check_error(err, "clGetPlatformIDs (count)");

  std::vector<cl_platform_id> platforms(num_platforms);
  err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
  check_error(err, "clGetPlatformIDs (fetch)");

  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<cl_device_id> 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";
    }
  }

  return 0;
}

------------------------------------------------------------------------------------->
//--9--opencl_utils.cpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#include "opencl_utils.hpp"
#include "globals.hpp"

#include <CL/cl.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <stdexcept>

namespace {

    //--Kleiner Fehler-Helper--

    bool cl_ok(cl_int err, const char* where) {
        if (err == CL_SUCCESS) return true;
        std::cerr << "❌ OpenCL Error " << err << " at " << where << "\n";
        return false;
    }

    //--Lese Datei in string--

    std::string read_file(const std::string &path) {
        std::ifstream ifs(path, std::ios::in | std::ios::binary);
        if (!ifs) throw std::runtime_error("Konnte Datei nicht öffnen: " + path);
        return std::string((std::istreambuf_iterator<char>(ifs)),
                            std::istreambuf_iterator<char>());
    }
}

//--Größe-Konstanten (gleiche Werte wie globals.hpp)--

constexpr size_t TARGET_SIZE_BYTES = 32;

void init_opencl(const std::string &kernel_path,
                 const std::string &kernel_func_name,
                 int platform_index,
                 int device_index,
                 int intensity,
                 GpuResources &resources) {

    cl_int err = CL_SUCCESS;

    //--Plattformen--

    cl_uint num_platforms = 0;
    err = clGetPlatformIDs(0, nullptr, &num_platforms);
    if (!cl_ok(err, "clGetPlatformIDs(count)")) std::exit(1);
    if (num_platforms == 0) {
        std::cerr << "❌ Keine OpenCL Plattformen gefunden\n";
        std::exit(1);
    }

    std::vector<cl_platform_id> platforms(num_platforms);
    err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
    if (!cl_ok(err, "clGetPlatformIDs(fetch)")) std::exit(1);
    if ((cl_uint)platform_index >= num_platforms) {
        std::cerr << "❌ Ungültiger Plattform-Index\n";
        std::exit(1);
    }

    cl_platform_id platform = platforms[platform_index];

    //--Devices--

    cl_uint num_devices = 0;
    err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, nullptr, &num_devices);
    if (!cl_ok(err, "clGetDeviceIDs(count)")) std::exit(1);
    if (num_devices == 0) {
        std::cerr << "❌ Keine OpenCL Geräte auf Plattform\n";
        std::exit(1);
    }

    std::vector<cl_device_id> devices(num_devices);
    err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, num_devices, devices.data(), nullptr);
    if (!cl_ok(err, "clGetDeviceIDs(fetch)")) std::exit(1);

    if ((cl_uint)device_index >= num_devices) {
        std::cerr << "❌ Ungültiger Geräte-Index\n";
        std::exit(1);
    }

    resources.device = devices[device_index];

    //--Kontext & Queue--

    resources.context = clCreateContext(nullptr, 1, &resources.device, nullptr, nullptr, &err);
    if (!cl_ok(err, "clCreateContext")) std::exit(1);

    resources.queue = clCreateCommandQueueWithProperties(resources.context, resources.device, nullptr, &err);
    if (!cl_ok(err, "clCreateCommandQueueWithProperties")) {
        clReleaseContext(resources.context);
        resources.context = nullptr;
        std::exit(1);
    }

    //--Kernel-Quelle lesen--

    std::string src;
    try {
        src = read_file(./XBTGPUARC/kernels/zhash.cl);
    } catch (const std::exception &e) {
        std::cerr << "❌ " << e.what() << "\n";
        cleanup_opencl(resources);
        std::exit(1);
    }

    const char* src_ptr = src.c_str();
    size_t src_size = src.size();

    resources.program = clCreateProgramWithSource(resources.context, 1, &src_ptr, &src_size, &err);
    if (!cl_ok(err, "clCreateProgramWithSource")) {
        cleanup_opencl(resources);
        std::exit(1);
    }

    //--Build-Optionen (modifizierbar)--

    const char* build_opts = "-cl-std=CL2.0 -cl-fast-relaxed-math";
    err = clBuildProgram(resources.program, 1, &resources.device, build_opts, nullptr, nullptr);

    //--Build-Log ausgeben wenn Fehler oder Info vorhanden--

    size_t log_size = 0;
    clGetProgramBuildInfo(resources.program, resources.device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
    if (log_size > 1) {
        std::vector<char> log(log_size + 1);
        clGetProgramBuildInfo(resources.program, resources.device, CL_PROGRAM_BUILD_LOG, log_size, log.data(), nullptr);
        std::cerr << "--- OpenCL Build Log ---\n" << log.data() << "\n------------------------\n";
    }

    if (!cl_ok(err, "clBuildProgram")) {
        cleanup_opencl(resources);
        std::exit(1);
    }

    //--Kernel erstellen--

    resources.kernel = clCreateKernel(resources.program, kernel_zhash.cl(), &err);
    if (!cl_ok(err, "clCreateKernel")) {
        cleanup_opencl(resources);
        std::exit(1);
    }

    //--Device-Memory Info (optional: anzeigen)--

    cl_ulong mem_total = 0;
    if (clGetDeviceInfo(resources.device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_total), &mem_total, nullptr) == CL_SUCCESS) {
        double mem_mib = mem_total / 1024.0 / 1024.0;
        std::cerr << "🧠 Device VRAM: " << std::fixed << std::setprecision(1) << mem_mib << " MiB\n";
    }

    //--Puffergrößen anlegen (INPUT_SIZE / HASH_SIZE aus globals.hpp)--

    size_t in_size = static_cast<size_t>(INPUT_SIZE) * std::max(1, intensity);
    size_t out_hashes_size = static_cast<size_t>(HASH_SIZE) * std::max(1, intensity);

    resources.input_buffer = clCreateBuffer(resources.context, CL_MEM_READ_WRITE, in_size, nullptr, &err);
    if (!cl_ok(err, "clCreateBuffer(input_buffer)")) { cleanup_opencl(resources); std::exit(1); }

    resources.output_hashes_buffer = clCreateBuffer(resources.context, CL_MEM_READ_WRITE, out_hashes_size, nullptr, &err);
    if (!cl_ok(err, "clCreateBuffer(output_hashes_buffer)")) { cleanup_opencl(resources); std::exit(1); }

    resources.pool_target_buffer = clCreateBuffer(resources.context, CL_MEM_READ_ONLY, TARGET_SIZE_BYTES, nullptr, &err);
    if (!cl_ok(err, "clCreateBuffer(pool_target_buffer)")) { cleanup_opencl(resources); std::exit(1); }

    std::cout << "✅ OpenCL initialisiert (Kernel: " << zhash.cl << ")\n";
}

void cleanup_opencl(GpuResources &resources) {
    if (resources.input_buffer) { clReleaseMemObject(resources.input_buffer); resources.input_buffer = nullptr; }
    if (resources.output_buffer) { clReleaseMemObject(resources.output_buffer); resources.output_buffer = nullptr; } // falls verwendet
    if (resources.output_hashes_buffer) { clReleaseMemObject(resources.output_hashes_buffer); resources.output_hashes_buffer = nullptr; }
    if (resources.pool_target_buffer) { clReleaseMemObject(resources.pool_target_buffer); resources.pool_target_buffer = nullptr; }

    if (resources.kernel) { clReleaseKernel(resources.kernel); resources.kernel = nullptr; }
    if (resources.program) { clReleaseProgram(resources.program); resources.program = nullptr; }
    if (resources.queue) { clReleaseCommandQueue(resources.queue); resources.queue = nullptr; }
    if (resources.context) { clReleaseContext(resources.context); resources.context = nullptr; }

    resources.device = nullptr;
}

------------------------------------------------------------------------------------->
//--10--opencl_utils.hpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#pragma once

#include <string>
#include <CL/cl.h>
#include "globals.hpp"

//--Initialisiert OpenCL (einheitliche Signatur)--
//--kernel_path: Pfad zur .cl Datei--
//--kernel_func_name: Name der Kernel-Funktion inside the .cl (z.B. "zhash.cl")--
//--platform_index / device_index: Auswahl--
//--intensity: wieviele Einheiten (wird für Puffergrößen verwendet)--

void init_opencl(const std::string& kernel_path,
                 const std::string& kernel_func_name,
                 int platform_index,
                 int device_index,
                 int intensity,
                 GpuResources& resources);

//--Gibt alle OpenCL-Ressourcen frei (sicher mehrfach aufrufbar)--

void cleanup_opencl(GpuResources& resources);

//--Schreibt das hex-Target in GPU-Puffer (bestehende Signatur)--

void update_opencl_target(const GpuResources& resources, const std::string& hex_target);

//--Optional: kleines Helfer-Interface zum Setzen der Kernel-Args (wenn benötigt)--

void set_kernel_args(const GpuResources& resources,
                     cl_mem solution_indexes_buffer,
                     uint32_t start_nonce);

------------------------------------------------------------------------------------->
//--11--run.sh--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#!/bin/bash

export GPU_MAX_HEAP_SIZE=100 //--
export GPU_MAX_USE_SYNC_OBJECTS=1 //--
export GPU_SINGLE_ALLOC_PERCENT=100 //--
export GPU_MAX_ALLOC_PERCENT=100 //--
export GPU_MAX_SINGLE_ALLOC_PERCENT=100 //--
export GPU_ENABLE_LARGE_ALLOCATION=100 //--
export GPU_MAX_WORKGROUP_SIZE=64 //--

./xbtgpuarc \ //--Startet das XBTGPUARC Mining Programm.--
    --platform 1 \ //--Wählt die Plattform aus, auf wlecher Gemined werden soll.--
    --device 0 \ //-Wählt die genaue Recheneinheit in Form der Intel ARC Grafikkarte mit dem DG2 Chip aus.--
    --algo zhash_144_5 \ //--Wählt den zu minenden Algoritmus aus--
    --pool solo-btg.2miners.com \ //--Wählt den Pool oder den Server aus, um mit dem Netzwerk zu Kommunizieren.--
    --port 4040 \ //--Wählt den PoolPort aus.--
    --wallet Gb4V4a9Jk3p8aH6jkW3Aq3sq8rQCuJQ6S8 \ //--Hier fügen Sie ihre eigene Mining Adressen ein!--
                                                                              //--Sehr Wichtig, da ansonsten die Belohnung an meine Person geht!--
    --worker A730m \ //--Hier sehen Sie die genaue Bezeichnung des ausgewählten ARC Computer Chips.--
    --password x \ //--Hier können Sie den Wert bei "x" Behalten. Es würde wohl kaum jemand ihre Wallet mit Geld durch seine Arbeit bei ihnen füllen wollen.--
    --intensity 256 //--HIer kann man Einstellen, wie Stark die Grafikkarte arbeiten soll!--
                          //--Ein Mittelhoher Wert ist in der Regel zu Präferieren, genaue Details zur ARC GPU Architektur stehen noch aus.--

-------------------------------------------------------------------------------------
//--12--stratum_notify_listener.cpp--
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#include "stratum_notify_listener.hpp"
#include "globals.hpp"
#include "miner_loop.hpp"
#include "notify_parser.hpp" //--Wir nutzen jetzt den externen Parser!--
#include "opencl_utils.hpp"

#include <boost/asio.hpp>
#include <boost/json.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

using boost::asio::ip::tcp;

 //--Globale Variablen, die von anderen Teilen des Programms gesetzt werden--

extern int next_request_id;
extern std::string current_job_id;
extern std::string worker_name;

 //--Funktion zum Senden eines gefundenen Shares an den Pool--

void submit_share(tcp::socket &socket, const std::string &nonce_hex,
                  const std::string &ntime_hex, const std::string &job_id) {
  using namespace boost::json;

  //--Erstellt die Parameter für die "mining.submit" Methode--

  array params;
  params.emplace_back(worker_name);
  params.emplace_back(job_id);
  params.emplace_back(
      "00000000"); //--extranonce2 Platzhalter, oft nicht benötigt--
  params.emplace_back(ntime_hex);
  params.emplace_back(nonce_hex);

  //--Baut die komplette JSON-RPC-Anfrage zusammen--

  object request;
  request["id"] = next_request_id++;
  request["method"] = "mining.submit";
  request["params"] = params;

  //--Sendet die Nachricht an den Pool--

  std::string message = serialize(request) + "\n";
  boost::asio::write(socket, boost::asio::buffer(message));
  std::cout << "📤 Share für Job " << job_id << " gesendet:\n" << message;
}

//--Hauptfunktion, die die Verbindung zum Stratum-Pool hält und auf Nachrichten lauscht--

void run_stratum_listener(const std::string &pool_host, int pool_port,
                          const std::string &wallet, const std::string &worker,
                          const std::string &password, int intensity,
                          GpuResources &gpu_resources) {
  const std::string port_str = std::to_string(pool_port);
  worker_name = wallet + "." + worker; //--Setzt den globalen Worker-Namen--

  try {
    boost::asio::io_context io_context;
    tcp::resolver resolver(io_context);
    auto endpoints = resolver.resolve(pool_host, port_str);
    tcp::socket socket(io_context);
    boost::asio::connect(socket, endpoints);

    std::cout << "📡 Verbunden mit " << pool_host << ":" << port_str << "\n";

    //--Standard-Nachrichten zur Anmeldung am Pool--

    std::string subscribe =
        R"({"id": 1, "method": "mining.subscribe", "params": []})"
        "\n";
    std::string authorize =
        R"({"id": 2, "method": "mining.authorize", "params": [")" +
        worker_name + R"(", ")" + password +
        R"("]})"
        "\n";

    boost::asio::write(socket, boost::asio::buffer(subscribe));
    boost::asio::write(socket, boost::asio::buffer(authorize));

    std::string buffer; //--Puffer für eingehende Daten vom Socket--
    static std::thread mining_thread;

    //--Endlosschleife zum Lesen von Nachrichten--

    for (;;) {
      char reply[4096];
      boost::system::error_code error;
      size_t len = socket.read_some(boost::asio::buffer(reply), error);
      if (len == 0 && error)
        break; //--Verbindung geschlossen oder Fehler--

      buffer.append(reply, len);
      size_t pos = 0;

      //--Verarbeite jede vollständige Zeile (getrennt durch '\n') im Puffer--

      while ((pos = buffer.find('\n')) != std::string::npos) {
        std::string line = buffer.substr(0, pos);
        buffer.erase(0, pos + 1);
        std::cout << "🌐 Nachricht:\n" << line << "\n";

        //--Versuch, die Nachricht als Mining-Job zu parsen--

        auto job_opt = parse_notify(line);

        if (job_opt) { //--Wenn ein gültiger Job empfangen wurde--
          auto &job = *job_opt;
          current_job_id = job.job_id; //--Update der globalen Job-ID--

          std::cout << "🎯 Job ID: " << job.job_id << "\n";
          std::cout << "🧱 PrevHash: " << job.prevhash << "\n";

          //--Stoppe den alten Mining-Prozess, falls er noch läuft--

          if (mining_thread.joinable()) {
            stop_mining();
            mining_thread.join();
          }

          //--Definiere eine Lambda-Funktion, die aufgerufen wird, wenn eine--
          //-Lösung gefunden wird!!!--

          auto share_submitter = [&](uint32_t nonce,
                                     const std::array<uint8_t, 32> &hash,
                                     const MiningJob &job) {
            std::stringstream ss_nonce;
            ss_nonce << std::hex << std::setw(8) << std::setfill('0') << nonce;

            //--Keine Umwandlung von job.ntime nötig, ist schon hex-String--

            submit_share(socket, ss_nonce.str(), job.ntime, job.job_id);
          };

          //--Starte den neuen Mining-Prozess in einem eigenen Thread--

          mining_thread = std::thread([&, job]() {
            miner_loop(job, share_submitter, gpu_resources, intensity);
          });
        }
      }
      if (error == boost::asio::error::eof)
        break;
      else if (error)
        throw boost::system::system_error(error);
    }

    if (mining_thread.joinable()) {
      stop_mining();
      mining_thread.join();
    }

  } catch (const std::exception &e) {
    std::cerr << "❌ Stratum-Fehler: " << e.what() << "\n";
  }
}

------------------------------------------------------------------------------------->
//--13--stratum_notify_listener.hpp--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->

#pragma once
#include "opencl_utils.hpp"
#include <string>

//--Startet Stratum-Connection, empfängt Jobs, startet Miner, horcht auf Arbeit vom Pool.--

void run_stratum_listener(const std::string &pool_host, int pool_port,
                          const std::string &wallet, const std::string &worker,
                          const std::string &password, int intensity,
                          GpuResources &gpu_resources); //--← NICHT const--
------------------------------------------------------------------------------------->

👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
authoralucian
permlinkxbtgpuarc-hauptprogramm-in-deutsch-erklahrt-und-ausgefuhrt
categorydeutsch
json_metadata{"app":"peakd/2025.9.1","format":"markdown","tags":["deutsch","xbtgpuarc","haupt","programm","zhash"],"users":[],"image":[]}
created2025-09-09 06:26:24
last_update2025-09-09 06:26:24
depth0
children0
last_payout2025-09-16 06:26:24
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.592 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length62,962
author_reputation195,391,863,533,776
root_title"XBTGPUARC Hauptprogramm in Deutsch erklährt und ausgeführt."
beneficiaries
0.
accountnull
weight10,000
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id145,652,751
net_rshares4,032,097,536,409
author_curate_reward""
vote details (30)