Compare commits
10 Commits
1501e6d65c
...
7f217df04f
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f217df04f | |||
| b6af554b0c | |||
| 8709072574 | |||
| 7d4096749a | |||
| b2f0090236 | |||
| b700b7b25d | |||
| 6be9e3cafd | |||
| 89dcee8951 | |||
| ef320a4397 | |||
| 5b4c11f6f0 |
25
.gitignore
vendored
25
.gitignore
vendored
@@ -1,8 +1,31 @@
|
||||
# Python/local environment (prototype legacy)
|
||||
__pycache__/
|
||||
**/__pycache__/
|
||||
venv/
|
||||
.venv/
|
||||
.pytest_cache/
|
||||
*.pyc
|
||||
*.pyo
|
||||
|
||||
# Local-only config
|
||||
miner.conf
|
||||
config.py
|
||||
|
||||
# C/C++ build artifacts
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Binaries produced by Makefile
|
||||
miner
|
||||
launcher
|
||||
miner.conf
|
||||
bench_hash
|
||||
test_sha256_backend
|
||||
test_miner_regression
|
||||
|
||||
# Profiling / PGO artifacts
|
||||
.pgo/
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.profraw
|
||||
*.profdata
|
||||
|
||||
53
Makefile
53
Makefile
@@ -1,10 +1,22 @@
|
||||
CC := gcc
|
||||
CFLAGS := -O3 -march=native -mtune=native -flto -fomit-frame-pointer -DNDEBUG -Wall -Wextra -std=c11 -D_GNU_SOURCE -D_POSIX_C_SOURCE=200809L
|
||||
LDFLAGS := -pthread -lcrypto -lm -flto
|
||||
PGO_DIR := .pgo
|
||||
|
||||
COMMON_OBJS := config.o utils.o json.o rpc.o types.o block_builder.o miner.o mining_loop.o
|
||||
SHA256_BACKEND_OBJS := sha256/sha256_backend.o
|
||||
HAS_ARM_CRYPTO := $(shell echo | $(CC) $(CFLAGS) -dM -E - 2>/dev/null | grep -c __ARM_FEATURE_CRYPTO)
|
||||
ifeq ($(shell uname -m),aarch64)
|
||||
ifneq ($(HAS_ARM_CRYPTO),0)
|
||||
SHA256_BACKEND_OBJS += sha256/sha256d80_4way_aarch64.o
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: all clean
|
||||
COMMON_OBJS := config.o utils.o json.o rpc.o types.o block_builder.o miner.o mining_loop.o $(SHA256_BACKEND_OBJS)
|
||||
BENCH_BIN := bench_hash
|
||||
TEST_SHA_BIN := test_sha256_backend
|
||||
TEST_MINER_BIN := test_miner_regression
|
||||
|
||||
.PHONY: all clean bench bench-5x test pgo-gen pgo-use pgo-clean
|
||||
|
||||
all: miner launcher
|
||||
|
||||
@@ -18,4 +30,39 @@ launcher: launcher.o $(COMMON_OBJS)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.o miner launcher
|
||||
rm -f *.o sha256/*.o bench/*.o tests/*.o miner launcher $(BENCH_BIN) $(TEST_SHA_BIN) $(TEST_MINER_BIN)
|
||||
|
||||
bench: $(BENCH_BIN)
|
||||
|
||||
$(BENCH_BIN): bench/bench_hash.o $(SHA256_BACKEND_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
bench-5x: $(BENCH_BIN)
|
||||
@i=1; while [ $$i -le 5 ]; do \
|
||||
echo "Run $$i/5"; \
|
||||
./$(BENCH_BIN) 60; \
|
||||
i=$$((i+1)); \
|
||||
done
|
||||
|
||||
$(TEST_SHA_BIN): tests/test_sha256_backend.o $(SHA256_BACKEND_OBJS) utils.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(TEST_MINER_BIN): tests/test_miner_regression.o miner.o $(SHA256_BACKEND_OBJS) utils.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test: $(TEST_SHA_BIN) $(TEST_MINER_BIN)
|
||||
./$(TEST_SHA_BIN)
|
||||
./$(TEST_MINER_BIN)
|
||||
|
||||
pgo-gen: CFLAGS += -fprofile-generate=$(PGO_DIR)
|
||||
pgo-gen: LDFLAGS += -fprofile-generate=$(PGO_DIR)
|
||||
pgo-gen: clean all
|
||||
@echo "Profilazione build pronta."
|
||||
@echo "Esegui il tuo workload manualmente, poi lancia: make pgo-use"
|
||||
|
||||
pgo-use: CFLAGS += -fprofile-use=$(PGO_DIR) -fprofile-correction
|
||||
pgo-use: LDFLAGS += -fprofile-use=$(PGO_DIR)
|
||||
pgo-use: clean all
|
||||
|
||||
pgo-clean:
|
||||
rm -rf $(PGO_DIR)
|
||||
|
||||
59
bench/bench_hash.c
Normal file
59
bench/bench_hash.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../sha256/sha256_backend.h"
|
||||
|
||||
static double now_seconds(void) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
uint8_t header_76[76];
|
||||
sha256d80_midstate_t mid;
|
||||
sha256_state_t states[4];
|
||||
uint32_t target_words[8];
|
||||
uint32_t nonce = 0;
|
||||
uint64_t hashes = 0;
|
||||
volatile uint32_t sink = 0;
|
||||
double seconds = 10.0;
|
||||
double t0;
|
||||
int i;
|
||||
|
||||
if (argc > 1) {
|
||||
seconds = strtod(argv[1], NULL);
|
||||
if (seconds <= 0.0) {
|
||||
seconds = 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 76; i++) {
|
||||
header_76[i] = (uint8_t)(i * 13 + 7);
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
target_words[i] = 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
sha256d80_midstate_init(&mid, header_76);
|
||||
|
||||
t0 = now_seconds();
|
||||
while ((now_seconds() - t0) < seconds) {
|
||||
uint32_t mask = sha256d80_scan_4way(&mid, nonce, target_words, states);
|
||||
|
||||
sink ^= states[0].h[0] ^ states[1].h[0] ^ states[2].h[0] ^ states[3].h[0] ^ mask;
|
||||
nonce += 4U;
|
||||
hashes += 4U;
|
||||
}
|
||||
|
||||
{
|
||||
double elapsed = now_seconds() - t0;
|
||||
double khs = (double)hashes / elapsed / 1000.0;
|
||||
printf("bench_hash: %.2f kH/s | hashes=%llu | sink=%08x\n", khs, (unsigned long long)hashes, sink);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
16
launcher.c
16
launcher.c
@@ -53,6 +53,7 @@ static void dashboard_print(DashboardState *st, int n) {
|
||||
long long total_attempts = 0;
|
||||
time_t now_t = time(NULL);
|
||||
char ts[64];
|
||||
char total_rate_buf[32];
|
||||
|
||||
if (st->lines_printed > 0) {
|
||||
clear_lines(st->lines_printed);
|
||||
@@ -64,13 +65,16 @@ static void dashboard_print(DashboardState *st, int n) {
|
||||
}
|
||||
|
||||
strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", localtime(&now_t));
|
||||
format_hashrate_khs(total_rate, total_rate_buf, sizeof(total_rate_buf));
|
||||
|
||||
printf("%s | MINING STATUS\n", ts);
|
||||
printf("========================================\n");
|
||||
printf("Total: %.2f kH/s | Attempts: %lld\n", total_rate, total_attempts);
|
||||
printf("Total: %s | Attempts: %lld\n", total_rate_buf, total_attempts);
|
||||
printf("----------------------------------------\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
printf("Worker %-2d: %.2f kH/s | Attempts: %lld\n", i, st->rates[i], st->attempts[i]);
|
||||
char worker_rate_buf[32];
|
||||
format_hashrate_khs(st->rates[i], worker_rate_buf, sizeof(worker_rate_buf));
|
||||
printf("Worker %-2d: %s | Attempts: %lld\n", i, worker_rate_buf, st->attempts[i]);
|
||||
}
|
||||
|
||||
st->lines_printed = 4 + n;
|
||||
@@ -228,6 +232,8 @@ static int aggregate_loop(WorkerProc *workers, int n) {
|
||||
double elapsed = now_seconds() - st.start_t;
|
||||
long long total_attempts = 0;
|
||||
double avg_rate;
|
||||
char winner_rate_buf[32];
|
||||
char avg_rate_buf[32];
|
||||
|
||||
if (st.lines_printed > 0) {
|
||||
clear_lines(st.lines_printed);
|
||||
@@ -238,6 +244,7 @@ static int aggregate_loop(WorkerProc *workers, int n) {
|
||||
}
|
||||
|
||||
avg_rate = (elapsed > 0.0) ? (double)total_attempts / elapsed / 1000.0 : 0.0;
|
||||
format_hashrate_khs(avg_rate, avg_rate_buf, sizeof(avg_rate_buf));
|
||||
|
||||
printf("==============================================================================\n");
|
||||
printf("[OK] BLOCK FOUND AND SUBMITTED\n");
|
||||
@@ -246,9 +253,10 @@ static int aggregate_loop(WorkerProc *workers, int n) {
|
||||
printf(" Worker: %d\n", st.winner_idx);
|
||||
}
|
||||
if (st.has_winner_rate) {
|
||||
printf(" Worker hashrate: %.2f kH/s\n", st.winner_rate);
|
||||
format_hashrate_khs(st.winner_rate, winner_rate_buf, sizeof(winner_rate_buf));
|
||||
printf(" Worker hashrate: %s\n", winner_rate_buf);
|
||||
}
|
||||
printf(" Average total hashrate: %.2f kH/s\n", avg_rate);
|
||||
printf(" Average total hashrate: %s\n", avg_rate_buf);
|
||||
printf(" Total attempts: %lld\n", total_attempts);
|
||||
printf("==============================================================================\n");
|
||||
|
||||
|
||||
210
miner.c
210
miner.c
@@ -1,99 +1,106 @@
|
||||
#include "miner.h"
|
||||
|
||||
#include <openssl/sha.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 = 5.0;
|
||||
static const double RATE_INTERVAL_SEC = 2.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 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 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]) {
|
||||
static void target_words_from_be(const uint8_t target_be[32], uint32_t out[8]) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
write_u32_be(out + i * 4, ctx->h[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 uint8_t target_be[32],
|
||||
const uint32_t target_words[8],
|
||||
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;
|
||||
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();
|
||||
|
||||
SHA256_Init(&init_ctx);
|
||||
first_chunk_ctx = init_ctx;
|
||||
SHA256_Transform(&first_chunk_ctx, header_76);
|
||||
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);
|
||||
|
||||
memset(block1, 0, sizeof(block1));
|
||||
memcpy(block1, header_76 + 64, 12);
|
||||
block1[16] = 0x80;
|
||||
block1[62] = 0x02;
|
||||
block1[63] = 0x80;
|
||||
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;
|
||||
}
|
||||
|
||||
memset(block2, 0, sizeof(block2));
|
||||
block2[32] = 0x80;
|
||||
block2[62] = 0x01;
|
||||
block2[63] = 0x00;
|
||||
i += 4U;
|
||||
}
|
||||
|
||||
for (i = 0; i < batch_size; i++) {
|
||||
SHA256_CTX ctx1;
|
||||
SHA256_CTX ctx2;
|
||||
uint32_t n = start_nonce + i;
|
||||
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;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -101,13 +108,6 @@ static int compute_hash_batch(
|
||||
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,
|
||||
@@ -120,12 +120,17 @@ int mine_block(
|
||||
MineResult *out
|
||||
) {
|
||||
uint8_t target_be[32];
|
||||
uint32_t target_words[8];
|
||||
uint32_t nonce;
|
||||
long long attempts = 0;
|
||||
time_t t_start;
|
||||
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));
|
||||
|
||||
@@ -133,6 +138,7 @@ int mine_block(
|
||||
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;
|
||||
@@ -140,30 +146,34 @@ int mine_block(
|
||||
nonce = (uint32_t)rand();
|
||||
}
|
||||
|
||||
t_start = time(NULL);
|
||||
last_rate_t = (double)t_start;
|
||||
last_tsu = (double)t_start;
|
||||
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];
|
||||
time_t now_t;
|
||||
double now;
|
||||
|
||||
if (atomic_load(stop_flag) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
now_t = time(NULL);
|
||||
now = (double)now_t;
|
||||
batch_count++;
|
||||
|
||||
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;
|
||||
/* 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_be, &found_nonce, found_digest)) {
|
||||
double total = now - (double)t_start;
|
||||
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;
|
||||
}
|
||||
@@ -182,18 +192,24 @@ int mine_block(
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ static void emit_eventf(int fd, const char *fmt, ...) {
|
||||
|
||||
static void status_callback(long long attempts, double hashrate_hz, void *ctx_ptr) {
|
||||
StatusCtx *ctx = (StatusCtx *)ctx_ptr;
|
||||
char rate_buf[32];
|
||||
|
||||
if (ctx->event_fd >= 0) {
|
||||
emit_eventf(ctx->event_fd, "status %d %.6f %lld\n", ctx->worker_idx, hashrate_hz / 1000.0, attempts);
|
||||
@@ -60,7 +61,8 @@ static void status_callback(long long attempts, double hashrate_hz, void *ctx_pt
|
||||
}
|
||||
|
||||
if (ctx->single_mode) {
|
||||
printf("\r[main] hashrate: %.2f kH/s | attempts: %lld", hashrate_hz / 1000.0, attempts);
|
||||
format_hashrate_hz(hashrate_hz, rate_buf, sizeof(rate_buf));
|
||||
printf("\r[main] hashrate: %s | attempts: %lld", rate_buf, attempts);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
1046
sha256/sha256_backend.c
Normal file
1046
sha256/sha256_backend.c
Normal file
File diff suppressed because it is too large
Load Diff
83
sha256/sha256_backend.h
Normal file
83
sha256/sha256_backend.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef SHA256_BACKEND_H
|
||||
#define SHA256_BACKEND_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Compact SHA256 state: only the 8 chaining words (32 bytes).
|
||||
* Avoids copying the bloated OpenSSL SHA256_CTX (~112 bytes) in the hot loop.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t h[8];
|
||||
} sha256_state_t;
|
||||
|
||||
typedef struct {
|
||||
sha256_state_t init_state;
|
||||
sha256_state_t first_chunk_state;
|
||||
uint8_t block1_template[64];
|
||||
uint8_t block2_template[64];
|
||||
} sha256d80_midstate_t;
|
||||
|
||||
/* Set state to SHA256 initial values (IV). */
|
||||
void sha256_state_init(sha256_state_t *state);
|
||||
|
||||
/* Serialize the 8 state words into a 32-byte big-endian digest. */
|
||||
void sha256_state_to_digest(const sha256_state_t *state, uint8_t out[32]);
|
||||
|
||||
/* Single SHA256 block compression (64-byte block). */
|
||||
void sha256_transform_fast(sha256_state_t *state, const uint8_t block[64]);
|
||||
|
||||
/*
|
||||
* 2-way interleaved SHA256 block compression.
|
||||
* Processes two independent (state, block) pairs so the CPU can overlap both
|
||||
* instruction chains. On non-ARM builds falls back to two sequential calls.
|
||||
*/
|
||||
void sha256_transform_fast_2way(
|
||||
sha256_state_t *stA, const uint8_t blkA[64],
|
||||
sha256_state_t *stB, const uint8_t blkB[64]
|
||||
);
|
||||
|
||||
/* Prepare SHA256d(80-byte header) midstate and constant blocks from header[0..75]. */
|
||||
void sha256d80_midstate_init(sha256d80_midstate_t *mid, const uint8_t header_76[76]);
|
||||
|
||||
/*
|
||||
* Hash 4 consecutive nonces with SHA256d(header80).
|
||||
* start_nonce lane order: [n, n+1, n+2, n+3].
|
||||
*/
|
||||
void sha256d80_hash_4way(
|
||||
const sha256d80_midstate_t *mid,
|
||||
uint32_t start_nonce,
|
||||
sha256_state_t out_states[4]
|
||||
);
|
||||
|
||||
/*
|
||||
* Hash 4 consecutive nonces and return hit mask against target words.
|
||||
* target_words are big-endian words target[0..7].
|
||||
* bit i set => lane i meets target.
|
||||
*/
|
||||
uint32_t sha256d80_scan_4way(
|
||||
const sha256d80_midstate_t *mid,
|
||||
uint32_t start_nonce,
|
||||
const uint32_t target_words[8],
|
||||
sha256_state_t out_states[4]
|
||||
);
|
||||
|
||||
/*
|
||||
* Ensure the SHA256 backend is initialized. Call once before using
|
||||
* sha256d80_scan_4way_direct() to avoid per-call pthread_once overhead.
|
||||
*/
|
||||
void sha256_backend_ensure_init(void);
|
||||
|
||||
/*
|
||||
* Like sha256d80_scan_4way() but skips the pthread_once check.
|
||||
* Caller MUST have called sha256_backend_ensure_init() (or any other
|
||||
* backend function) before calling this.
|
||||
*/
|
||||
uint32_t sha256d80_scan_4way_direct(
|
||||
const sha256d80_midstate_t *mid,
|
||||
uint32_t start_nonce,
|
||||
const uint32_t target_words[8],
|
||||
sha256_state_t out_states[4]
|
||||
);
|
||||
|
||||
#endif
|
||||
9
sha256/sha256d80_4way_aarch64.S
Normal file
9
sha256/sha256d80_4way_aarch64.S
Normal file
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.align 2
|
||||
|
||||
.global sha256d80_4way_aarch64_kernel
|
||||
.type sha256d80_4way_aarch64_kernel, %function
|
||||
sha256d80_4way_aarch64_kernel:
|
||||
b sha256d80_4way_aarch64_impl
|
||||
.size sha256d80_4way_aarch64_kernel, .-sha256d80_4way_aarch64_kernel
|
||||
|
||||
214
tests/test_miner_regression.c
Normal file
214
tests/test_miner_regression.c
Normal file
@@ -0,0 +1,214 @@
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../miner.h"
|
||||
#include "../sha256/sha256_backend.h"
|
||||
#include "../utils.h"
|
||||
|
||||
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 void sha256d_from_header76_nonce(const uint8_t header76[76], uint32_t nonce, uint8_t out[32]) {
|
||||
uint8_t header80[80];
|
||||
uint8_t block1[64];
|
||||
uint8_t block2[64];
|
||||
sha256_state_t init_state;
|
||||
sha256_state_t st1;
|
||||
sha256_state_t st2;
|
||||
|
||||
memcpy(header80, header76, 76);
|
||||
write_u32_le(header80 + 76, nonce);
|
||||
|
||||
sha256_state_init(&init_state);
|
||||
st1 = init_state;
|
||||
sha256_transform_fast(&st1, header80);
|
||||
|
||||
memset(block1, 0, sizeof(block1));
|
||||
memcpy(block1, header80 + 64, 16);
|
||||
block1[16] = 0x80;
|
||||
block1[62] = 0x02;
|
||||
block1[63] = 0x80;
|
||||
sha256_transform_fast(&st1, block1);
|
||||
|
||||
memset(block2, 0, sizeof(block2));
|
||||
sha256_state_to_digest(&st1, block2);
|
||||
block2[32] = 0x80;
|
||||
block2[62] = 0x01;
|
||||
block2[63] = 0x00;
|
||||
|
||||
st2 = init_state;
|
||||
sha256_transform_fast(&st2, block2);
|
||||
sha256_state_to_digest(&st2, out);
|
||||
}
|
||||
|
||||
static void digest_rev(const uint8_t digest[32], uint8_t rev[32]) {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
rev[i] = digest[31 - i];
|
||||
}
|
||||
}
|
||||
|
||||
static int find_record_nonce(
|
||||
const uint8_t header76[76],
|
||||
int parity,
|
||||
uint32_t min_nonce,
|
||||
uint32_t max_nonce,
|
||||
uint32_t *out_nonce,
|
||||
uint8_t out_target_be[32]
|
||||
) {
|
||||
uint8_t best[32];
|
||||
uint32_t n;
|
||||
|
||||
memset(best, 0xFF, sizeof(best));
|
||||
|
||||
for (n = 0; n <= max_nonce; n++) {
|
||||
uint8_t digest[32];
|
||||
uint8_t rev[32];
|
||||
|
||||
sha256d_from_header76_nonce(header76, n, digest);
|
||||
digest_rev(digest, rev);
|
||||
|
||||
if (memcmp(rev, best, 32) < 0) {
|
||||
memcpy(best, rev, 32);
|
||||
if (n >= min_nonce && ((int)(n & 1U) == parity)) {
|
||||
*out_nonce = n;
|
||||
memcpy(out_target_be, rev, 32);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_case(uint32_t batch, int parity) {
|
||||
uint8_t header76[76];
|
||||
uint8_t target_be[32];
|
||||
uint8_t expected_digest[32];
|
||||
MineResult out;
|
||||
atomic_int stop_flag;
|
||||
uint32_t expected_nonce;
|
||||
char *target_hex;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 76; i++) {
|
||||
header76[i] = (uint8_t)((i * 29 + 11) & 0xFF);
|
||||
}
|
||||
|
||||
if (!find_record_nonce(header76, parity, 4U, 150000U, &expected_nonce, target_be)) {
|
||||
fprintf(stderr, "[test_miner_regression] no record nonce found for parity=%d\n", parity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_hex = bytes_to_hex(target_be, 32);
|
||||
if (target_hex == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
atomic_init(&stop_flag, 0);
|
||||
rc = mine_block(
|
||||
header76,
|
||||
target_hex,
|
||||
"incremental",
|
||||
batch,
|
||||
0,
|
||||
&stop_flag,
|
||||
NULL,
|
||||
NULL,
|
||||
&out
|
||||
);
|
||||
free(target_hex);
|
||||
|
||||
if (rc == 0 || out.found == 0) {
|
||||
fprintf(stderr, "[test_miner_regression] mine_block failed for batch=%u\n", batch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out.nonce != expected_nonce) {
|
||||
fprintf(stderr, "[test_miner_regression] nonce mismatch batch=%u expected=%u got=%u\n",
|
||||
batch, expected_nonce, out.nonce);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sha256d_from_header76_nonce(header76, out.nonce, expected_digest);
|
||||
if (memcmp(expected_digest, out.digest, 32) != 0) {
|
||||
fprintf(stderr, "[test_miner_regression] digest mismatch for nonce=%u\n", out.nonce);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_easy_target_finds_zero(void) {
|
||||
uint8_t header76[76];
|
||||
char *target_hex = NULL;
|
||||
MineResult out;
|
||||
atomic_int stop_flag;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 76; i++) {
|
||||
header76[i] = (uint8_t)((i * 7 + 3) & 0xFF);
|
||||
}
|
||||
|
||||
target_hex = bytes_to_hex((const uint8_t[32]){
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
}, 32);
|
||||
if (target_hex == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
atomic_init(&stop_flag, 0);
|
||||
if (!mine_block(header76, target_hex, "incremental", 1, 0, &stop_flag, NULL, NULL, &out)) {
|
||||
free(target_hex);
|
||||
return 0;
|
||||
}
|
||||
free(target_hex);
|
||||
|
||||
return out.found == 1 && out.nonce == 0U;
|
||||
}
|
||||
|
||||
static int test_wrap_arithmetic(void) {
|
||||
uint32_t start = 0xFFFFFFFEU;
|
||||
uint32_t n0 = start + 0U;
|
||||
uint32_t n1 = start + 1U;
|
||||
uint32_t n2 = start + 2U;
|
||||
uint32_t n3 = start + 3U;
|
||||
|
||||
return n0 == 0xFFFFFFFEU &&
|
||||
n1 == 0xFFFFFFFFU &&
|
||||
n2 == 0x00000000U &&
|
||||
n3 == 0x00000001U;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
if (!test_easy_target_finds_zero()) {
|
||||
fprintf(stderr, "test_easy_target_finds_zero: FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
if (!run_case(5U, 1)) {
|
||||
fprintf(stderr, "run_case(batch=5, parity=1): FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
if (!run_case(6U, 0)) {
|
||||
fprintf(stderr, "run_case(batch=6, parity=0): FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
if (!test_wrap_arithmetic()) {
|
||||
fprintf(stderr, "test_wrap_arithmetic: FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("test_miner_regression: OK\n");
|
||||
return 0;
|
||||
}
|
||||
266
tests/test_sha256_backend.c
Normal file
266
tests/test_sha256_backend.c
Normal file
@@ -0,0 +1,266 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../sha256/sha256_backend.h"
|
||||
#include "../utils.h"
|
||||
|
||||
static uint32_t xorshift32(uint32_t *s) {
|
||||
uint32_t x = *s;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
*s = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
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 void fill_random(uint8_t *dst, size_t n, uint32_t *seed) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
dst[i] = (uint8_t)(xorshift32(seed) & 0xFFU);
|
||||
}
|
||||
}
|
||||
|
||||
static void backend_double_sha256_80(const uint8_t header80[80], uint8_t out[32]) {
|
||||
sha256_state_t init_state;
|
||||
sha256_state_t st1;
|
||||
sha256_state_t st2;
|
||||
uint8_t block1[64];
|
||||
uint8_t block2[64];
|
||||
|
||||
sha256_state_init(&init_state);
|
||||
|
||||
st1 = init_state;
|
||||
sha256_transform_fast(&st1, header80);
|
||||
|
||||
memset(block1, 0, sizeof(block1));
|
||||
memcpy(block1, header80 + 64, 16);
|
||||
block1[16] = 0x80;
|
||||
block1[62] = 0x02;
|
||||
block1[63] = 0x80;
|
||||
sha256_transform_fast(&st1, block1);
|
||||
|
||||
memset(block2, 0, sizeof(block2));
|
||||
sha256_state_to_digest(&st1, block2);
|
||||
block2[32] = 0x80;
|
||||
block2[62] = 0x01;
|
||||
block2[63] = 0x00;
|
||||
|
||||
st2 = init_state;
|
||||
sha256_transform_fast(&st2, block2);
|
||||
sha256_state_to_digest(&st2, out);
|
||||
}
|
||||
|
||||
static int test_transform_equivalence_random(void) {
|
||||
uint32_t seed = 0x12345678U;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
uint8_t block[64];
|
||||
SHA256_CTX ref;
|
||||
sha256_state_t test;
|
||||
|
||||
fill_random(block, sizeof(block), &seed);
|
||||
|
||||
SHA256_Init(&ref);
|
||||
sha256_state_init(&test);
|
||||
SHA256_Transform(&ref, block);
|
||||
sha256_transform_fast(&test, block);
|
||||
|
||||
if (memcmp(ref.h, test.h, sizeof(ref.h)) != 0) {
|
||||
fprintf(stderr, "[test_sha256_backend] transform mismatch at iter=%d\n", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_transform_2way_equivalence(void) {
|
||||
uint32_t seed = 0xCAFEBABEU;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5000; i++) {
|
||||
uint8_t block_a[64];
|
||||
uint8_t block_b[64];
|
||||
SHA256_CTX ref_a;
|
||||
SHA256_CTX ref_b;
|
||||
sha256_state_t test_a;
|
||||
sha256_state_t test_b;
|
||||
|
||||
fill_random(block_a, sizeof(block_a), &seed);
|
||||
fill_random(block_b, sizeof(block_b), &seed);
|
||||
|
||||
SHA256_Init(&ref_a);
|
||||
SHA256_Init(&ref_b);
|
||||
sha256_state_init(&test_a);
|
||||
sha256_state_init(&test_b);
|
||||
|
||||
SHA256_Transform(&ref_a, block_a);
|
||||
SHA256_Transform(&ref_b, block_b);
|
||||
sha256_transform_fast_2way(&test_a, block_a, &test_b, block_b);
|
||||
|
||||
if (memcmp(ref_a.h, test_a.h, sizeof(ref_a.h)) != 0 ||
|
||||
memcmp(ref_b.h, test_b.h, sizeof(ref_b.h)) != 0) {
|
||||
fprintf(stderr, "[test_sha256_backend] 2way mismatch at iter=%d\n", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_double_sha256_80_equivalence(void) {
|
||||
uint32_t seed = 0xA55AA55AU;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2048; i++) {
|
||||
uint8_t header80[80];
|
||||
uint8_t ref[32];
|
||||
uint8_t test[32];
|
||||
|
||||
fill_random(header80, sizeof(header80), &seed);
|
||||
double_sha256(header80, sizeof(header80), ref);
|
||||
backend_double_sha256_80(header80, test);
|
||||
|
||||
if (memcmp(ref, test, sizeof(ref)) != 0) {
|
||||
fprintf(stderr, "[test_sha256_backend] sha256d80 mismatch at iter=%d\n", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_sha256d80_4way_100k_nonces(void) {
|
||||
uint8_t header76[76];
|
||||
sha256d80_midstate_t mid;
|
||||
uint32_t base = 0x12340000U;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 76; i++) {
|
||||
header76[i] = (uint8_t)((i * 19 + 5) & 0xFF);
|
||||
}
|
||||
|
||||
sha256d80_midstate_init(&mid, header76);
|
||||
|
||||
for (i = 0; i < 25000; i++) {
|
||||
uint32_t start_nonce = base + (uint32_t)(i * 4);
|
||||
sha256_state_t states[4];
|
||||
int lane;
|
||||
|
||||
sha256d80_hash_4way(&mid, start_nonce, states);
|
||||
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
uint8_t header80[80];
|
||||
uint8_t ref[32];
|
||||
uint8_t got[32];
|
||||
uint32_t nonce = start_nonce + (uint32_t)lane;
|
||||
|
||||
memcpy(header80, header76, 76);
|
||||
write_u32_le(header80 + 76, nonce);
|
||||
double_sha256(header80, sizeof(header80), ref);
|
||||
sha256_state_to_digest(&states[lane], got);
|
||||
|
||||
if (memcmp(ref, got, 32) != 0) {
|
||||
fprintf(stderr, "[test_sha256_backend] 4way nonce mismatch nonce=%u lane=%d\n", nonce, lane);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_sha256d80_scan_4way_direct(void) {
|
||||
uint8_t header76[76];
|
||||
sha256d80_midstate_t mid;
|
||||
sha256_state_t st_ref[4];
|
||||
sha256_state_t st_direct[4];
|
||||
uint32_t all_max[8];
|
||||
uint32_t mask_ref;
|
||||
uint32_t mask_direct;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 76; i++) {
|
||||
header76[i] = (uint8_t)((i * 13 + 7) & 0xFF);
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
all_max[i] = 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
sha256d80_midstate_init(&mid, header76);
|
||||
sha256_backend_ensure_init();
|
||||
|
||||
mask_ref = sha256d80_scan_4way(&mid, 0x11223344U, all_max, st_ref);
|
||||
mask_direct = sha256d80_scan_4way_direct(&mid, 0x11223344U, all_max, st_direct);
|
||||
|
||||
if (mask_ref != mask_direct) {
|
||||
fprintf(stderr, "[test_sha256_backend] scan_4way_direct mask mismatch ref=%u direct=%u\n",
|
||||
mask_ref, mask_direct);
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(st_ref, st_direct, sizeof(st_ref)) != 0) {
|
||||
fprintf(stderr, "[test_sha256_backend] scan_4way_direct state mismatch\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_sha256d80_scan_hitmask_basic(void) {
|
||||
uint8_t header76[76];
|
||||
sha256d80_midstate_t mid;
|
||||
sha256_state_t states[4];
|
||||
uint32_t all_max[8];
|
||||
uint32_t all_zero[8];
|
||||
uint32_t mask_max;
|
||||
uint32_t mask_zero;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 76; i++) {
|
||||
header76[i] = (uint8_t)((i * 11 + 1) & 0xFF);
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
all_max[i] = 0xFFFFFFFFU;
|
||||
all_zero[i] = 0x00000000U;
|
||||
}
|
||||
|
||||
sha256d80_midstate_init(&mid, header76);
|
||||
mask_max = sha256d80_scan_4way(&mid, 0xABC00000U, all_max, states);
|
||||
mask_zero = sha256d80_scan_4way(&mid, 0xABC00000U, all_zero, states);
|
||||
|
||||
return mask_max == 0xFU && mask_zero == 0U;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
if (!test_transform_equivalence_random()) {
|
||||
return 1;
|
||||
}
|
||||
if (!test_transform_2way_equivalence()) {
|
||||
return 1;
|
||||
}
|
||||
if (!test_double_sha256_80_equivalence()) {
|
||||
return 1;
|
||||
}
|
||||
if (!test_sha256d80_4way_100k_nonces()) {
|
||||
return 1;
|
||||
}
|
||||
if (!test_sha256d80_scan_4way_direct()) {
|
||||
return 1;
|
||||
}
|
||||
if (!test_sha256d80_scan_hitmask_basic()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("test_sha256_backend: OK\n");
|
||||
return 0;
|
||||
}
|
||||
42
utils.c
42
utils.c
@@ -15,6 +15,48 @@ static char to_hex_digit(unsigned int v) {
|
||||
return (char)('a' + (v - 10U));
|
||||
}
|
||||
|
||||
static void format_hashrate_core(double rate_hs, char *out, size_t out_len) {
|
||||
static const char *units[] = {"H/s", "kH/s", "MH/s", "GH/s", "TH/s", "PH/s", "EH/s"};
|
||||
size_t unit_idx = 0;
|
||||
const size_t unit_count = sizeof(units) / sizeof(units[0]);
|
||||
double value;
|
||||
|
||||
if (out == NULL || out_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(rate_hs >= 0.0)) {
|
||||
rate_hs = 0.0;
|
||||
}
|
||||
value = rate_hs;
|
||||
|
||||
while (value >= 999.95 && unit_idx + 1 < unit_count) {
|
||||
value /= 1000.0;
|
||||
unit_idx++;
|
||||
}
|
||||
|
||||
while (value > 0.0 && value < 1.0 && unit_idx > 0) {
|
||||
value *= 1000.0;
|
||||
unit_idx--;
|
||||
}
|
||||
|
||||
if (value >= 100.0) {
|
||||
snprintf(out, out_len, "%.0f %s", value, units[unit_idx]);
|
||||
} else if (value >= 10.0) {
|
||||
snprintf(out, out_len, "%.1f %s", value, units[unit_idx]);
|
||||
} else {
|
||||
snprintf(out, out_len, "%.2f %s", value, units[unit_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
void format_hashrate_hz(double rate_hz, char *out, size_t out_len) {
|
||||
format_hashrate_core(rate_hz, out, out_len);
|
||||
}
|
||||
|
||||
void format_hashrate_khs(double rate_khs, char *out, size_t out_len) {
|
||||
format_hashrate_core(rate_khs * 1000.0, out, out_len);
|
||||
}
|
||||
|
||||
void sb_init(StrBuf *sb) {
|
||||
sb->data = NULL;
|
||||
sb->len = 0;
|
||||
|
||||
2
utils.h
2
utils.h
@@ -33,5 +33,7 @@ char *decode_nbits_hex(uint32_t nbits);
|
||||
char *calculate_target_hex(const char *bits_hex, double difficulty_factor, const char *network);
|
||||
|
||||
char *hex_add_width(const char *base_hex, int add_value);
|
||||
void format_hashrate_hz(double rate_hz, char *out, size_t out_len);
|
||||
void format_hashrate_khs(double rate_khs, char *out, size_t out_len);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user