Files
cpu-miner/tests/test_miner_regression.c

215 lines
5.3 KiB
C

#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;
}