#include #include #include #include #include #include #include #include #include #include // 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(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& 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::system_clock::now().time_since_epoch()).count(); // Create block headers for batch processing const size_t block_header_len = 80; std::vector block_headers(block_header_len * num_nonces); std::vector 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::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 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; }