==> 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}