skip to content
==> tests/sha256d.c <==
1/* sha256d on the simulator against @ajax/mesh-ref-sha256d: OP_INIT's genesis
2 * header and midstate; chunks ground on a 16-warp node, the node's best hash
3 * and every share (target 8 zero bits) equal to hashing each nonce on the CPU;
4 * the genesis block's own nonce found as a share with Bitcoin's genesis hash;
5 * config ops, stale chunks, the param rule, and the request window. */
6#include "mesh/check.h"
7#include "mesh/ref/sha256d.h"
8#include "mesh/rt/sim_mailbox.h"
9
10#include "../src/sha256d.c"
11
12#include <stdlib.h>
13
14#define CLOG 10u
15
16static uint8_t *mb, *view;
17
18static void le_bytes(const uint32_t *w, size_t n, uint8_t *out) {
19    for (size_t i = 0; i < n; i++)
20        for (int k = 0; k < 4; k++) out[4 * i + k] = (uint8_t)(w[i] >> (8 * k));
21}
22static void view_bytes(uint32_t off, uint32_t n, uint8_t *out) { for (uint32_t i = 0; i < n; i++) out[i] = view[off + i]; }
23
24/* One chunk (OP_JOB) against the CPU: shares, best, the job record. */
25static void check_chunk(uint64_t g, uint32_t zbits) {
26    uint8_t hdr[80], target[32];
27    view_bytes(SHA_V_HEADER, 80, hdr);
28    mesh_sha_zbits_target(zbits, target);
29    uint32_t base = mesh_sim_u32(view + SHA_V_BASE), time = mesh_sim_u32(view + SHA_V_HEADER + 68);
30    uint64_t p = g << CLOG;
31    uint32_t nonce0 = base + (uint32_t)p, ntime = time + (uint32_t)(p >> 32);
32    uint8_t best[32], h[32];
33    memset(best, 0xff, 32);
34    uint32_t best_nonce = 0, shares = 0, share_nonce[8] = {0};
35    for (uint32_t i = 0; i < (1u << CLOG); i++) {
36        mesh_sha_hash_at(hdr, nonce0 + i, ntime, h);
37        if (mesh_sha_le_lt(h, best)) { memcpy(best, h, 32); best_nonce = nonce0 + i; }
38        if (!mesh_sha_le_lt(target, h)) { if (shares < 8) share_nonce[shares] = nonce0 + i; shares++; }
39    }
40    uint32_t shares0 = mesh_sim_u32(view + SHA_V_SHARES);
41    mesh_sim_set_u64(view + SHA_V_JOB_BASE, g);
42    uint32_t t = mesh_sim_publish(mb, 0, MESH_OP_JOB, 0), r = 0;
43    CHECK(mesh_sim_wait(mb, 0, t, &r, 120000));
44    CHECK_U(r, shares);
45    CHECK_U(mesh_sim_u32(view + SHA_V_SHARES) - shares0, shares);
46    uint32_t rec = SHA_V_JOB_OUT + SHA_JOB_REC * (t % MESH_PROG_RESULTS);
47    CHECK_U(mesh_sim_u32(view + rec), shares);
48    for (uint32_t i = 0; i < shares && i < SHA_JOB_SHARES; i++) CHECK_U(mesh_sim_u32(view + rec + 4 + 8 * i), share_nonce[i]);
49    CHECK_U(mesh_sim_u32(view + rec + 4 + 8 * SHA_JOB_SHARES), ntime);
50    /* The view's best is the least so far; this chunk's best matches if it is the best. */
51    uint8_t vb[32];
52    view_bytes(SHA_V_BEST, 32, vb);
53    if (memcmp(vb, best, 32) == 0) CHECK_U(mesh_sim_u32(view + SHA_V_BEST_NONCE), best_nonce);
54    else CHECK(mesh_sha_le_lt(vb, best));
55}
56
57int main(void) {
58    mb = mesh_sim_mailbox();
59    mesh_sim_prog p = {.name = "sha256d", .view_bytes = 0x2000, .nodes = 1, .warps = 16, .shared_bytes = 0x60, .param = CLOG,
60                       .req_off = 0x800, .req_max = 0x200, .resp_off = 0xa00, .resp_max = 0x200};
61    view = mesh_sim_install(mb, 0, &p);
62    mesh_sim_launch *l = mesh_sim_launch_prog(mb, 0, &p, mesh_main);
63    CHECK_U(mesh_sim_call(mb, 0, MESH_OP_INIT, 0), MESH_R_NONE);
64    CHECK_U(mesh_sim_u32(view + SHA_V_MAGIC), SHA_MAGIC);
65    CHECK_U(mesh_sim_u32(view + SHA_V_CHUNK_LOG2), CLOG);
66    CHECK_U(mesh_sim_u32(view + SHA_V_TARGET_ZBITS), SHA_ZBITS_DEFAULT);
67    uint8_t g_hdr[80];
68    le_bytes(SHA_GENESIS, 20, g_hdr);
69    uint8_t hdr[80];
70    view_bytes(SHA_V_HEADER, 80, hdr);
71    CHECK(memcmp(hdr, g_hdr, 80) == 0);
72    CHECK_U(mesh_sim_u32(view + SHA_V_NBITS), 0x1d00ffffu);
73    /* The midstate: the first block's compression (sha256-compress). */
74    uint32_t st[8], blk[16];
75    memcpy(st, SHA256_H0, sizeof st);
76    for (int k = 0; k < 16; k++) blk[k] = (uint32_t)g_hdr[4 * k] << 24 | (uint32_t)g_hdr[4 * k + 1] << 16 | (uint32_t)g_hdr[4 * k + 2] << 8 | g_hdr[4 * k + 3];
77    sha256_compress(st, blk);
78    for (int k = 0; k < 8; k++) CHECK_U(mesh_sim_u32(view + SHA_V_MID + 4 * k), st[k]);
79    /* Chunks at 8 zero bits: a few shares each. */
80    CHECK_U(mesh_sim_call(mb, 0, SHA_OP_ZBITS, 8), MESH_R_NONE);
81    CHECK_U(mesh_sim_u32(view + SHA_V_TARGET_ZBITS), 8);
82    for (uint64_t g = 0; g < 3; g++) check_chunk(g, 8);
83    check_chunk((uint64_t)1 << 22, 8); /* time rolled: p >> 32 = 1 */
84    CHECK_U(mesh_sim_u64(view + SHA_V_HASHES), 4u << CLOG);
85    /* The genesis nonce, with the header's own target (nbits 1d00ffff): a share,
86     * and its hash is the genesis block's. */
87    CHECK_U(mesh_sim_call(mb, 0, SHA_OP_GENESIS, 0), MESH_R_NONE);
88    CHECK_U(mesh_sim_call(mb, 0, SHA_OP_BASE, MESH_SHA_GENESIS_NONCE - 100), MESH_R_NONE);
89    mesh_sim_set_u64(view + SHA_V_JOB_BASE, 0);
90    uint32_t t = mesh_sim_publish(mb, 0, MESH_OP_JOB, 0), r = 0;
91    CHECK(mesh_sim_wait(mb, 0, t, &r, 120000));
92    CHECK_U(r, 1);
93    CHECK_U(mesh_sim_u32(view + SHA_V_LAST_NONCE), MESH_SHA_GENESIS_NONCE);
94    CHECK_U(mesh_sim_u32(view + SHA_V_BEST_NONCE), MESH_SHA_GENESIS_NONCE);
95    uint8_t best[32];
96    char disp[65];
97    view_bytes(SHA_V_BEST, 32, best);
98    mesh_sha_display(best, disp);
99    CHECK_S(disp, MESH_SHA_GENESIS_HASH);
100    /* Bad config args; the chunk op is refused. */
101    CHECK_U(mesh_sim_call(mb, 0, SHA_OP_ZBITS, 0), MESH_R_BAD_OP);
102    CHECK_U(mesh_sim_call(mb, 0, SHA_OP_CHUNK, 12), MESH_R_BAD_OP);
103    CHECK_U(mesh_sim_call(mb, 0, SHA_OP_NBITS, 0x1d80ffffu), MESH_R_BAD_OP); /* negative */
104    CHECK_U(mesh_sim_call(mb, 0, MESH_OP_TASK, 0), MESH_R_BAD_OP);
105    /* The request window. */
106    char out[512];
107    uint32_t n = 0;
108    const char *st_req = "status";
109    mesh_sim_request(mb, 0, st_req, (uint32_t)strlen(st_req), out, sizeof out - 1, &n);
110    CHECK(n != UINT32_MAX);
111    out[n] = 0;
112    char want[256];
113    snprintf(want, sizeof want, " zbits=32 base=%u chunk_log2=10 time=1231006505 hashes=", MESH_SHA_GENESIS_NONCE - 100);
114    CHECK(strncmp(out, "ok gen=", 7) == 0 && strstr(out, want) != NULL);
115    CHECK(strstr(out, " best=" MESH_SHA_GENESIS_HASH "\n") != NULL);
116    const char *bad = "zbits 300";
117    mesh_sim_request(mb, 0, bad, (uint32_t)strlen(bad), out, sizeof out - 1, &n);
118    out[n] = 0;
119    CHECK_S(out, "err zbits: 1..=255\n");
120    const char *ch = "chunk 12";
121    mesh_sim_request(mb, 0, ch, (uint32_t)strlen(ch), out, sizeof out - 1, &n);
122    out[n] = 0;
123    CHECK_S(out, "err chunk: fixed by the manifest's param (one chunk size on every member of a cluster)\n");
124    const char *zr = "zbits 12 base 5 reset";
125    mesh_sim_request(mb, 0, zr, (uint32_t)strlen(zr), out, sizeof out - 1, &n);
126    out[n] = 0;
127    CHECK(strncmp(out, "ok gen=", 7) == 0 && strstr(out, " zbits=12 base=5 ") != NULL);
128    CHECK_U(mesh_sim_u64(view + SHA_V_HASHES), 0);
129    /* A raw 80-byte header (not starting with a lowercase letter). */
130    mesh_sim_request(mb, 0, g_hdr, 80, out, sizeof out - 1, &n);
131    out[n] = 0;
132    CHECK(strncmp(out, "ok gen=", 7) == 0);
133    /* A param outside 6..=24 fails every chunk. */
134    CHECK_U(mesh_sim_u32(mesh_sim_ctl(mb, 0) + MESH_P_FAULT), 0);
135    mesh_sim_halt(mb, 0, l);
136    mesh_sim_prog q = p;
137    q.param = 5;
138    mesh_sim_install(mb, 0, &q);
139    l = mesh_sim_launch_prog(mb, 0, &q, mesh_main);
140    CHECK_U(mesh_sim_call(mb, 0, MESH_OP_JOB, 0), MESH_R_JOB_FAIL);
141    mesh_sim_halt(mb, 0, l);
142    mesh_sim_mailbox_free(mb);
143    return mesh_check_done();
144}