200 lines
4.9 KiB
C
200 lines
4.9 KiB
C
#include "miner.h"
|
|
|
|
#include <openssl/sha.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#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;
|
|
}
|
|
}
|
|
}
|