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=1024
./xbtgpuarc --platform 0 --device 0 --algo zhash_144_5 --pool solo-btg.2miners.com --port 4040 --wallet Gb4V4a9Jk3p8aH6jkW3Aq3sq8rQCuJQ6S8 --worker A730m --password x --intensity 4
Makefile
CXX = g++
CXXFLAGS = -std=c++17 -Wall -O2
LDFLAGS = -lOpenCL
SRC = main.cpp
OUT = xbtgpuarc
all:
$(CXX) $(CXXFLAGS) $(SRC) -o $(OUT) $(LDFLAGS)
clean:
rm -f $(OUT)
main.cpp
#include "notify_parser.hpp"
#include "mining_job.hpp"
#include <boost/asio.hpp>
#include
#include
#include
#include
#include
#include <CL/cl.h>
// --- OpenCL Setup und Kernel-Ausführung ---
void run_kernel(int platform_index, int device_index, int intensity) {
cl_int err;
// Plattformen ermitteln
cl_uint num_platforms = 0;
err = clGetPlatformIDs(0, nullptr, &num_platforms);
if (err != CL_SUCCESS || num_platforms == 0) {
std::cerr << "OpenCL: Keine Plattformen gefunden.\n";
return;
}
std::vector<cl_platform_id> platforms(num_platforms);
err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Fehler beim Abrufen der Plattformen.\n";
return;
}
if (platform_index >= (int)num_platforms) {
std::cerr << "OpenCL: Ungültiger Plattform-Index.\n";
return;
}
cl_platform_id platform = platforms[platform_index];
// Devices der Plattform abfragen
cl_uint num_devices = 0;
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &num_devices);
if (err != CL_SUCCESS || num_devices == 0) {
std::cerr << "OpenCL: Keine GPU Devices gefunden.\n";
return;
}
std::vector<cl_device_id> devices(num_devices);
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, num_devices, devices.data(), nullptr);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Fehler beim Abrufen der Devices.\n";
return;
}
if (device_index >= (int)num_devices) {
std::cerr << "OpenCL: Ungültiger Device-Index.\n";
return;
}
cl_device_id device = devices[device_index];
// Kontext und Command Queue
cl_context context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Kontext konnte nicht erstellt werden.\n";
return;
}
cl_command_queue queue = clCreateCommandQueue(context, device, 0, &err);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Command Queue konnte nicht erstellt werden.\n";
clReleaseContext(context);
return;
}
// Kernel-Datei laden
std::ifstream kernel_file("kernels/zhash_144_5.cl");
if (!kernel_file.is_open()) {
std::cerr << "OpenCL: Kernel-Datei nicht gefunden.\n";
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
std::string kernel_source((std::istreambuf_iterator<char>(kernel_file)),
std::istreambuf_iterator<char>());
const char* kernel_source_cstr = kernel_source.c_str();
cl_program program = clCreateProgramWithSource(context, 1, &kernel_source_cstr, nullptr, &err);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Programm konnte nicht erstellt werden.\n";
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
if (err != CL_SUCCESS) {
size_t log_size = 0;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
std::vector<char> log(log_size);
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, log.data(), nullptr);
std::cerr << "OpenCL: Build Fehler:\n" << log.data() << "\n";
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
cl_kernel kernel = clCreateKernel(program, "zhash_144_5", &err);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Kernel konnte nicht erstellt werden.\n";
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
size_t input_size = intensity * 4;
size_t output_size = intensity * 4;
std::vector<unsigned char> input(input_size, 0);
std::vector<unsigned char> output(output_size, 0);
for (int i = 0; i < (int)input_size; ++i) {
input[i] = static_cast<unsigned char>(i & 0xFF);
}
cl_mem input_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, input_size, input.data(), &err);
cl_mem output_buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, output_size, nullptr, &err);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Buffer konnte nicht erstellt werden.\n";
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
err = clSetKernelArg(kernel, 0, sizeof(int), &intensity);
err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &input_buffer);
err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &output_buffer);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Kernel-Argumente konnten nicht gesetzt werden.\n";
clReleaseMemObject(input_buffer);
clReleaseMemObject(output_buffer);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
size_t global_work_size = intensity;
err = clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, &global_work_size, nullptr, 0, nullptr, nullptr);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Kernel konnte nicht gestartet werden.\n";
clReleaseMemObject(input_buffer);
clReleaseMemObject(output_buffer);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
return;
}
clFinish(queue);
err = clEnqueueReadBuffer(queue, output_buffer, CL_TRUE, 0, output_size, output.data(), 0, nullptr, nullptr);
if (err != CL_SUCCESS) {
std::cerr << "OpenCL: Ergebnisse konnten nicht gelesen werden.\n";
} else {
std::cout << "🔑 Kernel Output:\n";
for (int i = 0; i < (int)intensity; ++i) {
std::cout << " [" << i << "]: ";
for (int b = 0; b < 4; ++b) {
printf("%02x", output[i * 4 + b]);
}
std::cout << "\n";
}
}
clReleaseMemObject(input_buffer);
clReleaseMemObject(output_buffer);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
}
// --- connect_to_pool Funktion ---
void connect_to_pool(const std::string& host, int port, const std::string& wallet,
const std::string& worker, const std::string& password) {
using boost::asio::ip::tcp;
try {
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(host, std::to_string(port));
tcp::socket socket(io_context);
boost::asio::connect(socket, endpoints);
std::cout << "📡 Verbunden mit " << host << ":" << port << "\n";
// mining.subscribe
std::string subscribe = R"({"id": 1, "method": "mining.subscribe", "params": []})" "\n";
boost::asio::write(socket, boost::asio::buffer(subscribe));
std::string full_user = wallet + "." + worker;
std::string authorize = R"({"id": 2, "method": "mining.authorize", "params": [")"
+ full_user + R"(", ")" + password + R"("]})" "\n";
boost::asio::write(socket, boost::asio::buffer(authorize));
// Initialantworten lesen (z. B. bis zu 5 Zeilen)
boost::asio::streambuf response_buf;
std::istream socket_stream(&response_buf);
std::string line;
for (int i = 0; i < 5; ++i) {
boost::asio::read_until(socket, response_buf, "\n");
while (std::getline(socket_stream, line)) {
if (!line.empty() && line.back() == '\r')
line.pop_back();
std::cout << "⛏️ Server: " << line << std::endl;
}
}
// Empfangsloop für weitere Nachrichten
std::string buffer;
for (;;) {
char reply[4096];
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(reply), error);
buffer.append(reply, len);
size_t pos = 0;
while ((pos = buffer.find('\n')) != std::string::npos) {
std::string line = buffer.substr(0, pos);
buffer.erase(0, pos + 1);
auto job = parse_notify(line);
if (job) {
std::cout << "🎯 Job ID: " << job->job_id << "\n";
std::cout << "🧱 PrevHash: " << job->prevhash << "\n";
}
std::cout << "🌐 Nachricht:\n" << line << "\n";
}
if (error == boost::asio::error::eof) break;
else if (error) throw boost::system::system_error(error);
}
} catch (const std::exception& e) {
std::cerr << "❌ Fehler: " << e.what() << "\n";
}
}
// --- main ---
int main(int argc, char** argv) {
int platform_index = 0;
int device_index = 0;
int intensity = 4;
std::string algo = "zhash_144_5";
std::string wallet = "default_wallet";
std::string worker = "default_worker";
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]);
}
std::cout << "🚀 Starte XBTGPUARC mit Algo: " << algo << "\n";
std::cout << "🎛️ Platform: " << platform_index << " | Device: " << device_index << " | Intensity: " << intensity << "\n";
std::cout << "👤 Worker: " << wallet << "." << worker << "\n";
connect_to_pool(pool_host, pool_port, wallet, worker, password);
run_kernel(platform_index, device_index, intensity);
return 0;
}
stratum_client.cpp
#include
#include
#include
#include
#include
#include
#include <netinet/in.h>
#include
#include <arpa/inet.h>
#include <sys/socket.h>
bool connect_to_pool(const std::string& host, int port, const std::string& wallet, const std::string& worker) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
std::cerr << "❌ Socket-Fehler\n";
return false;
}
struct hostent* server = gethostbyname(host.c_str());
if (!server) {
std::cerr << "❌ Host nicht gefunden: " << host << "\n";
return false;
}
sockaddr_in serv_addr {};
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
std::memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
std::cout << "📞 Verbinde zu " << host << ":" << port << "...\n";
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
std::cerr << "❌ Verbindung fehlgeschlagen\n";
return false;
}
// Subscribe senden
std::string subscribe = "{\"id\":1,\"method\":\"mining.subscribe\",\"params\":[]}\n";
send(sock, subscribe.c_str(), subscribe.size(), 0);
// Authorize senden
std::ostringstream auth;
auth << "{\"id\":2,\"method\":\"mining.authorize\",\"params\":[\""
<< wallet << "." << worker << "\",\"\"]}\n";
std::string auth_str = auth.str();
send(sock, auth_str.c_str(), auth_str.size(), 0);
// Mitlesen
char buffer[4096];
while (true) {
int n = read(sock, buffer, sizeof(buffer) - 1);
if (n <= 0) break;
buffer[n] = '\0';
std::cout << "📨 Pool: " << buffer << std::endl;
}
close(sock);
return true;
}
stratum_notify_listener.cpp
#include "notify_parser.hpp"
#include
#include <boost/asio.hpp>
#include
using boost::asio::ip::tcp;
int main() {
const std::string pool_host = "solo-btg.2miners.com";
const std::string pool_port = "4040";
const std::string wallet = "Gb4V4a9Jk3p8aH6jkW3Aq3sq8rQCuJQ6S8";
const std::string worker = "XBTGPUARC";
const std::string password = "x";
const std::string full_user = wallet + "." + worker;
try {
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(pool_host, pool_port);
tcp::socket socket(io_context);
boost::asio::connect(socket, endpoints);
std::cout << "📡 Verbunden mit " << pool_host << ":" << pool_port << "\n";
// mining.subscribe senden
std::string subscribe = "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": []}\n";
std::string authorize = "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"" +
full_user + "\", \"" + password + "\"]}\n";
// Empfangsschleife
std::string buffer;
for (;;) {
char reply[4096];
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(reply), error);
buffer.append(reply, len);
// Zeilenweise verarbeiten
size_t pos = 0;
while ((pos = buffer.find('\n')) != std::string::npos) {
std::string line = buffer.substr(0, pos);
buffer.erase(0, pos + 1);
auto job = parse_notify(line);
if (job) {
std::cout << "🎯 Job ID: " << job->job_id << std::endl;
std::cout << "🧱 PrevHash: " << job->prevhash << std::endl;
}
std::cout << "🌐 Nachricht:\n" << line << "\n";
}
if (error == boost::asio::error::eof) break;
else if (error) throw boost::system::system_error(error);
}
return 0;
}
notify_parser.hpp
#pragma once
#include
#include <boost/json.hpp>
#include
#include
#include
#include
#include
struct MiningJob {
std::string job_id;
std::string prevhash;
std::string coinbase1;
std::string coinbase2;
std::vector<std::string> merkle_branch;
std::string version; // hex string
std::string bits; // hex string
std::string ntime; // hex string
bool clean_jobs;
};
inline std::string to_hex(uint32_t val) {
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(8) << val;
return ss.str();
}
inline std::optional parse_notify(const std::string& json_string) {
using namespace boost::json;
try {
value parsed = parse(json_string);
if (!parsed.is_object()) return std::nullopt;
auto& obj = parsed.as_object();
if (!obj.contains("method") || obj["method"].as_string() != "mining.notify") return std::nullopt;
auto& params = obj["params"].as_array();
if (params.size() != 9) return std::nullopt;
MiningJob job;
job.job_id = std::string(params[0].as_string().c_str());
job.prevhash = std::string(params[1].as_string().c_str());
job.coinbase1 = std::string(params[2].as_string().c_str());
job.coinbase2 = std::string(params[3].as_string().c_str());
for (const auto& entry : params[4].as_array()) {
job.merkle_branch.emplace_back(entry.as_string().c_str());
}
job.version = to_hex(static_cast<uint32_t>(params[5].as_int64()));
job.bits = to_hex(static_cast<uint32_t>(params[6].as_int64()));
job.ntime = to_hex(static_cast<uint32_t>(params[7].as_int64()));
job.clean_jobs = params[8].as_bool();
return job;
} catch (const std::exception& e) {
std::cerr << "❌ JSON-Parsing Fehler: " << e.what() << "\n";
return std::nullopt;
}
}
mining_job.hpp
Unvollständig!!!
{
"id": 4,
"method": "mining.submit",
"params": [
"wallet.worker",
"660047748007180",
"00000000", // Nonce (hex)
"8e9f7d68" // nTime (hex)
]
}
std::vector<uint8_t> bits_to_target(uint32_t bits) {
uint32_t exponent = bits >> 24;
uint32_t mantissa = bits & 0xFFFFFF;
std::vector<uint8_t> target(32, 0); // 256 Bit (32 Bytes)
int shift = exponent - 3;
if (shift < 0 || shift > 29) return target; // Sanity check
target[shift + 0] = (mantissa >> 16) & 0xFF;
target[shift + 1] = (mantissa >> 8) & 0xFF;
target[shift + 2] = (mantissa >> 0) & 0xFF;
return target;
}
Unvollständig bis hier hin
Ordner: Kernels /Folgender Inhalt: zhash_144_5.cpp
__constant uint IV[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
inline uint rotl32(uint x, uint n) {
return (x << n) | (x >> (32 - n));
}
inline void G(uint *a, uint *b, uint *c, uint *d, uint r1, uint r2) {
*a = *a + *b;
*d ^= *a;
d = rotl32(d, r1);
*c = *c + *d;
*b ^= *c;
*b = rotl32(*b, r2);
}
__kernel void zhash_144_5(int intensity, __global uchar* input, __global uchar* output) {
int gid = get_global_id(0);
if (gid >= intensity) return;
// Ladung von 4 Bytes Input als uint
uint msg = (uint)(
input[gid * 4 + 0] |
(input[gid * 4 + 1] << 8) |
(input[gid * 4 + 2] << 16) |
(input[gid * 4 + 3] << 24)
);
// Mini-Hash-Simulation (Blake-ähnlich)
uint a = IV[0] ^ msg;
uint b = IV[1] ^ gid;
uint c = IV[2] ^ (msg >> 1);
uint d = IV[3] ^ ((msg << 1) | gid);
// 4 Runden G
G(&a, &b, &c, &d, 16, 12);
G(&a, &b, &c, &d, 8, 7);
G(&a, &b, &c, &d, 10, 3);
G(&a, &b, &c, &d, 14, 5);
// Schreibe finalen Mix als Output (nur a+b+c+d kombiniert, klar sichtbar)
uint result = a ^ b ^ c ^ d;
output[gid * 4 + 0] = (uchar)((result >> 0) & 0xFF);
output[gid * 4 + 1] = (uchar)((result >> 8) & 0xFF);
output[gid * 4 + 2] = (uchar)((result >> 16) & 0xFF);
output[gid * 4 + 3] = (uchar)((result >> 24) & 0xFF);
}
Ordner: Logs Folgender Inahlt: Nichts
Die Formatierung muss man Selbst machen. Eigentlich alles. Keine Garantie und kein Support. Ich hoffe den Rest heute noch Fertig zu bekommen damit ich die Github Version hochladen kann, welche dann auch schon produktiv Einsatzfähig ist.