268 lines
8.8 KiB
C++
268 lines
8.8 KiB
C++
#include <iostream>
|
|
#include <iomanip>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include <dlfcn.h>
|
|
#include <cstring>
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
|
|
// HIP/ROCm runtime check (using dlopen, no direct headers needed)
|
|
|
|
// Forward declarations for GPU functions
|
|
extern "C" {
|
|
void rinhash_hip(const uint8_t* input, size_t input_len, uint8_t* output);
|
|
void rinhash_hip_batch(const uint8_t* block_headers, size_t block_header_len,
|
|
uint8_t* outputs, uint32_t num_blocks);
|
|
void RinHash(const uint32_t* version, const uint32_t* prev_block,
|
|
const uint32_t* merkle_root, const uint32_t* timestamp,
|
|
const uint32_t* bits, const uint32_t* nonce, uint8_t* output);
|
|
}
|
|
|
|
class GPURinHashMiner {
|
|
private:
|
|
void* gpu_lib_handle;
|
|
bool gpu_available;
|
|
|
|
// Function pointers for GPU operations
|
|
decltype(&rinhash_hip) gpu_rinhash;
|
|
decltype(&rinhash_hip_batch) gpu_rinhash_batch;
|
|
decltype(&RinHash) gpu_RinHash;
|
|
|
|
// Mining parameters
|
|
uint32_t version;
|
|
uint32_t prev_block[8];
|
|
uint32_t merkle_root[8];
|
|
uint32_t timestamp;
|
|
uint32_t bits;
|
|
uint32_t target[8];
|
|
|
|
// Mining statistics
|
|
uint64_t hashes_computed;
|
|
uint64_t start_time;
|
|
double hashrate;
|
|
|
|
public:
|
|
GPURinHashMiner() : gpu_lib_handle(nullptr), gpu_available(false),
|
|
hashes_computed(0), hashrate(0.0) {
|
|
loadGPULibrary();
|
|
initializeMiningParams();
|
|
}
|
|
|
|
~GPURinHashMiner() {
|
|
if (gpu_lib_handle) {
|
|
dlclose(gpu_lib_handle);
|
|
}
|
|
}
|
|
|
|
bool isGPUAvailable() const {
|
|
return gpu_available;
|
|
}
|
|
|
|
bool loadGPULibrary() {
|
|
// Try to load the GPU library
|
|
std::cout << "Attempting to load GPU library..." << std::endl;
|
|
gpu_lib_handle = dlopen("./rocm-direct-output/gpu-libs/librinhash_hip.so", RTLD_LAZY);
|
|
if (!gpu_lib_handle) {
|
|
std::cerr << "Failed to load GPU library: " << dlerror() << std::endl;
|
|
std::cerr << "Make sure to run: sudo cp rocm-direct-output/gpu-libs/librinhash_hip.so /usr/local/lib/" << std::endl;
|
|
std::cerr << "Current working directory: " << std::filesystem::current_path() << std::endl;
|
|
return false;
|
|
}
|
|
std::cout << "GPU library loaded successfully!" << std::endl;
|
|
|
|
// Load function pointers
|
|
std::cout << "Loading GPU functions..." << std::endl;
|
|
gpu_rinhash = (decltype(gpu_rinhash))dlsym(gpu_lib_handle, "rinhash_hip");
|
|
gpu_rinhash_batch = (decltype(gpu_rinhash_batch))dlsym(gpu_lib_handle, "rinhash_hip_batch");
|
|
gpu_RinHash = (decltype(gpu_RinHash))dlsym(gpu_lib_handle, "RinHash");
|
|
|
|
if (!gpu_rinhash) std::cerr << "Failed to load rinhash_hip" << std::endl;
|
|
if (!gpu_rinhash_batch) std::cerr << "Failed to load rinhash_hip_batch" << std::endl;
|
|
if (!gpu_RinHash) std::cerr << "Failed to load RinHash" << std::endl;
|
|
|
|
if (!gpu_rinhash || !gpu_rinhash_batch || !gpu_RinHash) {
|
|
std::cerr << "Failed to load GPU functions: " << dlerror() << std::endl;
|
|
dlclose(gpu_lib_handle);
|
|
gpu_lib_handle = nullptr;
|
|
return false;
|
|
}
|
|
std::cout << "GPU functions loaded successfully!" << std::endl;
|
|
|
|
// GPU availability will be verified by successful library loading
|
|
// and function calls working properly
|
|
|
|
std::cout << "GPU functions ready for mining" << std::endl;
|
|
|
|
gpu_available = true;
|
|
return true;
|
|
}
|
|
|
|
void initializeMiningParams() {
|
|
// Initialize with some default values for testing
|
|
version = 1;
|
|
timestamp = static_cast<uint32_t>(std::time(nullptr));
|
|
bits = 0x1d00ffff; // Default difficulty
|
|
|
|
// Initialize arrays to zero
|
|
memset(prev_block, 0, sizeof(prev_block));
|
|
memset(merkle_root, 0, sizeof(merkle_root));
|
|
memset(target, 0, sizeof(target));
|
|
|
|
// Set a reasonable target
|
|
target[7] = 0x0000ffff; // Easy difficulty for testing
|
|
}
|
|
|
|
void setBlockHeader(const std::vector<uint8_t>& block_header) {
|
|
if (block_header.size() != 80) {
|
|
std::cerr << "Invalid block header size: " << block_header.size() << std::endl;
|
|
return;
|
|
}
|
|
|
|
// Parse block header
|
|
memcpy(&version, &block_header[0], 4);
|
|
memcpy(prev_block, &block_header[4], 32);
|
|
memcpy(merkle_root, &block_header[36], 32);
|
|
memcpy(×tamp, &block_header[68], 4);
|
|
memcpy(&bits, &block_header[72], 4);
|
|
}
|
|
|
|
bool mineNonce(uint32_t start_nonce, uint32_t num_nonces, uint32_t& found_nonce) {
|
|
if (!gpu_available) {
|
|
std::cerr << "GPU not available" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
start_time = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now().time_since_epoch()).count();
|
|
|
|
// Create block headers for batch processing
|
|
const size_t block_header_len = 80;
|
|
std::vector<uint8_t> block_headers(block_header_len * num_nonces);
|
|
std::vector<uint8_t> hashes(32 * num_nonces);
|
|
|
|
// Fill block headers with different nonces
|
|
for (uint32_t i = 0; i < num_nonces; i++) {
|
|
uint32_t current_nonce = start_nonce + i;
|
|
uint8_t* header = block_headers.data() + i * block_header_len;
|
|
|
|
// Copy base header
|
|
memcpy(header, &version, 4);
|
|
memcpy(header + 4, prev_block, 32);
|
|
memcpy(header + 36, merkle_root, 32);
|
|
memcpy(header + 68, ×tamp, 4);
|
|
memcpy(header + 72, &bits, 4);
|
|
memcpy(header + 76, ¤t_nonce, 4);
|
|
}
|
|
|
|
// Process batch on GPU
|
|
if (gpu_rinhash_batch) {
|
|
gpu_rinhash_batch(block_headers.data(), block_header_len, hashes.data(), num_nonces);
|
|
} else {
|
|
std::cerr << "GPU batch function not available" << std::endl;
|
|
return false;
|
|
}
|
|
hashes_computed += num_nonces;
|
|
|
|
// Check results
|
|
for (uint32_t i = 0; i < num_nonces; i++) {
|
|
uint8_t* hash = hashes.data() + i * 32;
|
|
|
|
// Check if hash meets target (simple check for now)
|
|
bool meets_target = true;
|
|
for (int j = 0; j < 32; j++) {
|
|
if (hash[j] < target[j]) {
|
|
meets_target = true;
|
|
break;
|
|
} else if (hash[j] > target[j]) {
|
|
meets_target = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (meets_target) {
|
|
found_nonce = start_nonce + i;
|
|
updateHashrate();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
updateHashrate();
|
|
return false;
|
|
}
|
|
|
|
void updateHashrate() {
|
|
uint64_t current_time = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now().time_since_epoch()).count();
|
|
|
|
double elapsed_seconds = (current_time - start_time) / 1000.0;
|
|
if (elapsed_seconds > 0) {
|
|
hashrate = hashes_computed / elapsed_seconds;
|
|
}
|
|
}
|
|
|
|
double getHashrate() const {
|
|
return hashrate;
|
|
}
|
|
|
|
uint64_t getHashesComputed() const {
|
|
return hashes_computed;
|
|
}
|
|
|
|
void printStats() const {
|
|
std::cout << "GPU RinHash Miner Stats:" << std::endl;
|
|
std::cout << " GPU Available: " << (gpu_available ? "Yes" : "No") << std::endl;
|
|
std::cout << " Hashes Computed: " << hashes_computed << std::endl;
|
|
std::cout << " Hashrate: " << std::fixed << std::setprecision(2) << (hashrate / 1000.0) << " KH/s" << std::endl;
|
|
}
|
|
};
|
|
|
|
int main(int argc, char* argv[]) {
|
|
std::cout << "===================================" << std::endl;
|
|
std::cout << " RinHash GPU Miner" << std::endl;
|
|
std::cout << "===================================" << std::endl;
|
|
std::cout << std::endl;
|
|
|
|
GPURinHashMiner miner;
|
|
|
|
if (!miner.isGPUAvailable()) {
|
|
std::cerr << "GPU mining not available. Exiting." << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
// Initialize with a test block header
|
|
std::vector<uint8_t> test_header(80, 0);
|
|
miner.setBlockHeader(test_header);
|
|
|
|
std::cout << "Starting GPU mining test..." << std::endl;
|
|
std::cout << "Press Ctrl+C to stop" << std::endl;
|
|
std::cout << std::endl;
|
|
|
|
uint32_t start_nonce = 0;
|
|
const uint32_t batch_size = 100000; // Process 100k nonces per batch
|
|
uint32_t found_nonce = 0;
|
|
|
|
while (true) {
|
|
if (miner.mineNonce(start_nonce, batch_size, found_nonce)) {
|
|
std::cout << "Found nonce: " << found_nonce << std::endl;
|
|
break;
|
|
}
|
|
|
|
start_nonce += batch_size;
|
|
|
|
// Print stats every 10 batches
|
|
if ((start_nonce / batch_size) % 10 == 0) {
|
|
miner.printStats();
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
std::cout << "GPU mining completed!" << std::endl;
|
|
miner.printStats();
|
|
|
|
return 0;
|
|
}
|