Replace time() syscall with clock_gettime(CLOCK_MONOTONIC_COARSE) and gate timestamp/rate checks behind a batch counter to avoid clock overhead on every iteration. Set reporting interval to 2s.
216 lines
6.3 KiB
C
216 lines
6.3 KiB
C
#include "miner.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <stddef.h>
|
|
|
|
#include "sha256/sha256_backend.h"
|
|
#include "utils.h"
|
|
|
|
static const double RATE_INTERVAL_SEC = 2.0;
|
|
|
|
static inline uint32_t load_u32_be(const uint8_t *p) {
|
|
return ((uint32_t)p[0] << 24) |
|
|
((uint32_t)p[1] << 16) |
|
|
((uint32_t)p[2] << 8) |
|
|
(uint32_t)p[3];
|
|
}
|
|
|
|
static void target_words_from_be(const uint8_t target_be[32], uint32_t out[8]) {
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
out[i] = load_u32_be(target_be + i * 4);
|
|
}
|
|
}
|
|
|
|
static inline void write_u32_le(uint8_t *dst, uint32_t v) {
|
|
dst[0] = (uint8_t)(v & 0xFFU);
|
|
dst[1] = (uint8_t)((v >> 8) & 0xFFU);
|
|
dst[2] = (uint8_t)((v >> 16) & 0xFFU);
|
|
dst[3] = (uint8_t)((v >> 24) & 0xFFU);
|
|
}
|
|
|
|
static int compute_hash_batch(
|
|
const uint8_t header_76[76],
|
|
uint32_t start_nonce,
|
|
uint32_t batch_size,
|
|
const uint32_t target_words[8],
|
|
uint32_t *found_nonce,
|
|
uint8_t found_digest[32]
|
|
) {
|
|
sha256d80_midstate_t mid;
|
|
uint32_t i = 0;
|
|
sha256d80_midstate_init(&mid, header_76);
|
|
/* Backend is now initialized; use direct scan to skip per-call pthread_once */
|
|
sha256_backend_ensure_init();
|
|
|
|
while ((batch_size - i) >= 4U) {
|
|
uint32_t n0 = start_nonce + i;
|
|
sha256_state_t st1[4];
|
|
uint32_t mask = sha256d80_scan_4way_direct(&mid, n0, target_words, st1);
|
|
|
|
if (mask & 1U) {
|
|
*found_nonce = n0;
|
|
sha256_state_to_digest(&st1[0], found_digest);
|
|
return 1;
|
|
}
|
|
if (mask & 2U) {
|
|
*found_nonce = n0 + 1U;
|
|
sha256_state_to_digest(&st1[1], found_digest);
|
|
return 1;
|
|
}
|
|
if (mask & 4U) {
|
|
*found_nonce = n0 + 2U;
|
|
sha256_state_to_digest(&st1[2], found_digest);
|
|
return 1;
|
|
}
|
|
if (mask & 8U) {
|
|
*found_nonce = n0 + 3U;
|
|
sha256_state_to_digest(&st1[3], found_digest);
|
|
return 1;
|
|
}
|
|
|
|
i += 4U;
|
|
}
|
|
|
|
if (i < batch_size) {
|
|
uint32_t n0 = start_nonce + i;
|
|
uint32_t remain = batch_size - i;
|
|
uint32_t valid_mask = (1U << remain) - 1U;
|
|
sha256_state_t st1[4];
|
|
uint32_t mask = sha256d80_scan_4way(&mid, n0, target_words, st1) & valid_mask;
|
|
|
|
if (mask & 1U) {
|
|
*found_nonce = n0;
|
|
sha256_state_to_digest(&st1[0], found_digest);
|
|
return 1;
|
|
}
|
|
if (mask & 2U) {
|
|
*found_nonce = n0 + 1U;
|
|
sha256_state_to_digest(&st1[1], found_digest);
|
|
return 1;
|
|
}
|
|
if (mask & 4U) {
|
|
*found_nonce = n0 + 2U;
|
|
sha256_state_to_digest(&st1[2], found_digest);
|
|
return 1;
|
|
}
|
|
if (mask & 8U) {
|
|
*found_nonce = n0 + 3U;
|
|
sha256_state_to_digest(&st1[3], found_digest);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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 target_words[8];
|
|
uint32_t nonce;
|
|
long long attempts = 0;
|
|
struct timespec ts_start, ts_now;
|
|
double last_rate_t;
|
|
long long last_rate_n = 0;
|
|
double last_tsu;
|
|
uint32_t batch_count = 0;
|
|
/* Check timestamp update every 32 batches, rate every 32 batches (~1s) */
|
|
#define TSU_CHECK_MASK 31U
|
|
#define RATE_CHECK_MASK 31U
|
|
|
|
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;
|
|
}
|
|
target_words_from_be(target_be, target_words);
|
|
|
|
if (strcmp(nonce_mode, "incremental") == 0) {
|
|
nonce = 0;
|
|
} else {
|
|
nonce = (uint32_t)rand();
|
|
}
|
|
|
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts_start);
|
|
last_rate_t = (double)ts_start.tv_sec + (double)ts_start.tv_nsec * 1e-9;
|
|
last_tsu = last_rate_t;
|
|
|
|
while (1) {
|
|
uint32_t found_nonce = 0;
|
|
uint8_t found_digest[32];
|
|
|
|
if (atomic_load(stop_flag) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
batch_count++;
|
|
|
|
/* Timestamp update: check every 64 batches to reduce clock calls */
|
|
if (timestamp_update_interval > 0 && (batch_count & TSU_CHECK_MASK) == 0) {
|
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts_now);
|
|
double now = (double)ts_now.tv_sec + (double)ts_now.tv_nsec * 1e-9;
|
|
if (now - last_tsu >= (double)timestamp_update_interval) {
|
|
write_u32_le(header_76 + 68, (uint32_t)ts_now.tv_sec);
|
|
last_tsu = now;
|
|
}
|
|
}
|
|
|
|
if (compute_hash_batch(header_76, nonce, batch_size, target_words, &found_nonce, found_digest)) {
|
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts_now);
|
|
double total = ((double)ts_now.tv_sec + (double)ts_now.tv_nsec * 1e-9)
|
|
- ((double)ts_start.tv_sec + (double)ts_start.tv_nsec * 1e-9);
|
|
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;
|
|
|
|
/* Rate reporting: check every 128 batches */
|
|
if ((batch_count & RATE_CHECK_MASK) == 0) {
|
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts_now);
|
|
double now = (double)ts_now.tv_sec + (double)ts_now.tv_nsec * 1e-9;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
#undef TSU_CHECK_MASK
|
|
#undef RATE_CHECK_MASK
|
|
}
|