XBTGPUARC Miner Version 2000 :-) 535 Zeilen Wahnsinn.^^

Words
914
Reading
5 min
Listen
Play
1y

stratum_client.cpp:

#include
#include
#include
#include
#include
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#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;

}

miner_loop.cpp:

// miner_loop.cpp
#include "miner_loop.hpp"
#include <CL/cl.h>
#include
#include
#include
#include
#include

static cl_context context = nullptr;
static cl_command_queue queue = nullptr;
static cl_kernel kernel = nullptr;
static cl_program program = nullptr;
static cl_device_id device = nullptr;

// Kernel-Name
static const char* KERNEL_NAME = "zhash_144_5";

// Initialisiert OpenCL & lädt Kernel
void init_opencl() {
if (context) return; // Schon initialisiert

cl_int err;
cl_platform_id platform;
clGetPlatformIDs(1, &platform, nullptr);
clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);

context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
queue = clCreateCommandQueueWithProperties(context, device, 0, &err);

std::ifstream file("kernels/zhash.cl");
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
const char* src = source.c_str();
size_t size = source.size();

program = clCreateProgramWithSource(context, 1, &src, &size, &err);
clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);

kernel = clCreateKernel(program, KERNEL_NAME, &err);

}

// Miner-Loop: führt Kernel aus & prüft Hash < Target
void miner_loop(const MiningJob& job,
const std::function<void(uint32_t nonce, const std::array<uint8_t, 32>& hash)>& on_valid_share) {

init_opencl();

std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution<uint32_t> dist;

std::vector<uint8_t> target = bits_to_target(std::stoul(job.bits, nullptr, 16));
const int batch_size = 4096;

std::vector<cl_uchar> input_buffer(512 * batch_size);
std::vector<cl_uchar> output_buffer(32 * batch_size);

cl_int err;
cl_mem cl_input = clCreateBuffer(context, CL_MEM_READ_ONLY, input_buffer.size(), nullptr, &err);
cl_mem cl_output = clCreateBuffer(context, CL_MEM_WRITE_ONLY, output_buffer.size(), nullptr, &err);

clSetKernelArg(kernel, 0, sizeof(int), &batch_size);
clSetKernelArg(kernel, 1, sizeof(cl_mem), &cl_input);
clSetKernelArg(kernel, 2, sizeof(cl_mem), &cl_output);

while (true) {
    uint32_t start_nonce = dist(rng);

    for (int i = 0; i < batch_size; ++i) {
        uint32_t nonce = start_nonce + i;
        cl_uchar* in = &input_buffer[i * 512];
        in[0] = nonce & 0xFF;
        in[1] = (nonce >> 8) & 0xFF;
        in[2] = (nonce >> 16) & 0xFF;
        in[3] = (nonce >> 24) & 0xFF;
        // Rest des Buffers bleibt Dummy (kann durch coinbase ersetzt werden)
    }

    clEnqueueWriteBuffer(queue, cl_input, CL_TRUE, 0, input_buffer.size(), input_buffer.data(), 0, nullptr, nullptr);
    size_t global_work_size = batch_size;
    clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, &global_work_size, nullptr, 0, nullptr, nullptr);
    clFinish(queue);
    clEnqueueReadBuffer(queue, cl_output, CL_TRUE, 0, output_buffer.size(), output_buffer.data(), 0, nullptr, nullptr);

    for (int i = 0; i < batch_size; ++i) {
        std::array<uint8_t, 32> hash;
        std::memcpy(hash.data(), &output_buffer[i * 32], 32);
        if (is_valid_hash(hash, target)) {
            uint32_t nonce = start_nonce + i;
            on_valid_share(nonce, hash);
        }
    }
}

// Optional: Freigeben (falls du willst)
// clReleaseMemObject(cl_input);
// clReleaseMemObject(cl_output);
// clReleaseKernel(kernel);
// clReleaseProgram(program);
// clReleaseCommandQueue(queue);
// clReleaseContext(context);

}

miner_loop.hpp:

// miner_loop.hpp
#pragma once
#include "mining_job.hpp"
#include
#include
#include

void miner_loop(const MiningJob& job,
const std::function<void(uint32_t nonce, const std::array<uint8_t, 32>& hash)>& on_valid_share);

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 4096

Makefile

CXX = g++
CXXFLAGS = -std=c++17 -Wall -O2
LDFLAGS = -lOpenCL -lboost_json -lpthread

SRC = main.cpp miner_loop.cpp
OUT = xbtgpuarc

all:
$(CXX) $(CXXFLAGS) $(SRC) -o $(OUT) $(LDFLAGS)

clean:
rm -f $(OUT)

notify_parser.hpp:

#pragma once
#include "mining_job.hpp"
#include <boost/json.hpp>
#include
#include
#include
#include

inline std::string to_hex(uint32_t val) {
std::ostringstream ss;
ss << std::hex << std::setw(8) << std::setfill('0') << 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    = params[0].as_string().c_str();
    job.prevhash  = params[1].as_string().c_str();
    job.coinbase1 = params[2].as_string().c_str();
    job.coinbase2 = 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-Fehler: " << e.what() << "\n";
    return std::nullopt;
}

}

mining_job.hpp:

#pragma once
#include
#include
#include
#include

// Struktur für einen Mining-Job (aus mining.notify)
struct MiningJob {
std::string job_id;
std::string prevhash;
std::string coinbase1;
std::string coinbase2;
std::vector<std::string> merkle_branch;
std::string version;
std::string bits;
std::string ntime;
bool clean_jobs;
};

// Wandelt "bits" (compact target) in echtes 256-bit Target (32 Byte)
inline std::vector<uint8_t> bits_to_target(uint32_t bits) {
int exponent = bits >> 24;
uint32_t mantissa = bits & 0x007fffff;
std::vector<uint8_t> target(32, 0);

int shift = exponent - 3;
if (shift >= 0 && shift <= 29) {
    target[shift]     = (mantissa >> 16) & 0xff;
    target[shift + 1] = (mantissa >> 8) & 0xff;
    target[shift + 2] = mantissa & 0xff;
}

return target;

}

// Vergleicht 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 false; // Gleichstand ist kein gültiger Share
}

main.cpp:

#include <boost/asio.hpp>
#include <CL/cl.h>
#include
#include
#include
#include
#include
#include
#include

#include "notify_parser.hpp"
#include "mining_job.hpp"
#include "miner_loop.hpp"

void connect_to_pool(const std::string& host, int port,
const std::string& wallet,
const std::string& worker,
const std::string& password,
int platform_index,
int device_index,
int intensity) {
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";

    std::string subscribe = R"({"id":1,"method":"mining.subscribe","params":[]})" "\n";
    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(subscribe));
    boost::asio::write(socket, boost::asio::buffer(authorize));

    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 << "🎯 Neuer Job: " << job->job_id << "\n";

                miner_loop(*job, [](uint32_t nonce, const std::array<uint8_t, 32>& hash) {
                    std::cout << "✅ Share gefunden! Nonce = " << nonce << "\n";
                    // TODO: submit_share(job, nonce, hash);
                });
            }

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

}

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;

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, platform_index, device_index, intensity);

return 0;

}

kernels:

__constant uint IV[8] = {
0x6a09e667, 0xbb67ae85, 0x0a6ef372, 0x0a54ff5a,
0x510e527f, 0xb056688c, 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 m) {
*a = *a + *b + m;
*d ^= *a;
d = rotl32(d, 16);

*c = *c + *d;
*b ^= *c;
*b = rotl32(*b, 12);

*a = *a + *b + m;
*d ^= *a;
*d = rotl32(*d, 8);

*c = *c + *d;
*b ^= *c;
*b = rotl32(*b, 7);

}

__kernel void zhash_kernel(__global const uchar *input, __global uchar *output) {
int gid = get_global_id(0);

// Beispielhafte Initialwerte (einfach IV kopiert, z.B. Blake-Vorbild)
uint a = IV[0];
uint b = IV[1];
uint c = IV[2];
uint d = IV[3];

// Beispielhafte Nachrichtendaten (real aus input)
uint m = ((uint*)input)[gid];

// Mehrere Runden simuliert (feste Zahl z.B. 4)
for (int i = 0; i < 4; ++i) {
    G(&a, &b, &c, &d, m ^ i);
}

// Output berechnen (einfache Reduktion, sonst wird’s zu groß)
uint result = a ^ b ^ c ^ d;

// 4 Byte rausschreiben
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);

}

logs

XBTGPUARC Miner Version 2000 :-) 535 Zeilen Wahnsinn.^^ | Ecency