#include "miner.h" #include #include #include #include #include #include "utils.h" static const double RATE_INTERVAL_SEC = 5.0; static int hash_meets_target(const uint8_t digest[32], const uint8_t target_be[32]) { int i; for (i = 0; i < 32; i++) { uint8_t hb = digest[31 - i]; if (hb < target_be[i]) { return 1; } if (hb > target_be[i]) { return 0; } } return 1; } static void write_u32_be(uint8_t *dst, uint32_t v) { dst[0] = (uint8_t)((v >> 24) & 0xFF); dst[1] = (uint8_t)((v >> 16) & 0xFF); dst[2] = (uint8_t)((v >> 8) & 0xFF); dst[3] = (uint8_t)(v & 0xFF); } static void sha256_ctx_to_digest(const SHA256_CTX *ctx, uint8_t out[32]) { int i; for (i = 0; i < 8; i++) { write_u32_be(out + i * 4, ctx->h[i]); } } static int compute_hash_batch( const uint8_t header_76[76], uint32_t start_nonce, uint32_t batch_size, const uint8_t target_be[32], uint32_t *found_nonce, uint8_t found_digest[32] ) { SHA256_CTX init_ctx; SHA256_CTX first_chunk_ctx; uint8_t block1[64]; uint8_t block2[64]; uint8_t digest1[32]; uint8_t digest2[32]; uint32_t i; SHA256_Init(&init_ctx); first_chunk_ctx = init_ctx; SHA256_Transform(&first_chunk_ctx, header_76); memset(block1, 0, sizeof(block1)); memcpy(block1, header_76 + 64, 12); block1[16] = 0x80; block1[62] = 0x02; block1[63] = 0x80; memset(block2, 0, sizeof(block2)); block2[32] = 0x80; block2[62] = 0x01; block2[63] = 0x00; for (i = 0; i < batch_size; i++) { SHA256_CTX ctx1; SHA256_CTX ctx2; uint32_t n = start_nonce + i; block1[12] = (uint8_t)(n & 0xFF); block1[13] = (uint8_t)((n >> 8) & 0xFF); block1[14] = (uint8_t)((n >> 16) & 0xFF); block1[15] = (uint8_t)((n >> 24) & 0xFF); ctx1 = first_chunk_ctx; SHA256_Transform(&ctx1, block1); sha256_ctx_to_digest(&ctx1, digest1); memcpy(block2, digest1, 32); ctx2 = init_ctx; SHA256_Transform(&ctx2, block2); sha256_ctx_to_digest(&ctx2, digest2); if (hash_meets_target(digest2, target_be)) { *found_nonce = n; memcpy(found_digest, digest2, 32); return 1; } } return 0; } static void write_u32_le(uint8_t *dst, uint32_t v) { dst[0] = (uint8_t)(v & 0xFF); dst[1] = (uint8_t)((v >> 8) & 0xFF); dst[2] = (uint8_t)((v >> 16) & 0xFF); dst[3] = (uint8_t)((v >> 24) & 0xFF); } int mine_block( uint8_t header_76[76], const char *target_hex, const char *nonce_mode, uint32_t batch_size, int timestamp_update_interval, atomic_int *stop_flag, mine_status_cb status_cb, void *status_ctx, MineResult *out ) { uint8_t target_be[32]; uint32_t nonce; long long attempts = 0; time_t t_start; double last_rate_t; long long last_rate_n = 0; double last_tsu; memset(out, 0, sizeof(*out)); if (hex_to_fixed_bytes(target_hex, target_be, 32) == 0) { fprintf(stderr, "[miner] target hex non valido\n"); return 0; } if (strcmp(nonce_mode, "incremental") == 0) { nonce = 0; } else { nonce = (uint32_t)rand(); } t_start = time(NULL); last_rate_t = (double)t_start; last_tsu = (double)t_start; while (1) { uint32_t found_nonce = 0; uint8_t found_digest[32]; time_t now_t; double now; if (atomic_load(stop_flag) != 0) { return 0; } now_t = time(NULL); now = (double)now_t; if (timestamp_update_interval > 0 && (now - last_tsu) >= (double)timestamp_update_interval) { write_u32_le(header_76 + 68, (uint32_t)now_t); last_tsu = now; } if (compute_hash_batch(header_76, nonce, batch_size, target_be, &found_nonce, found_digest)) { double total = now - (double)t_start; if (total <= 0.0) { total = 1e-6; } out->found = 1; out->nonce = found_nonce; out->attempts = attempts + batch_size; out->hashrate_hz = (double)out->attempts / total; memcpy(out->header, header_76, 76); write_u32_le(out->header + 76, found_nonce); memcpy(out->digest, found_digest, 32); return 1; } attempts += batch_size; nonce += batch_size; now = (double)time(NULL); if ((now - last_rate_t) >= RATE_INTERVAL_SEC) { double dt = now - last_rate_t; if (dt <= 0.0) { dt = 1e-6; } if (status_cb != NULL) { double hr = (double)(attempts - last_rate_n) / dt; status_cb(attempts, hr, status_ctx); } last_rate_t = now; last_rate_n = attempts; } } }