skip to content
==> src/hashjob.c <==
1/* hashjob: a CPU job program (job arrays, docs/plan-fleet-scheduling.md F5) for the wasm executor
2 * (alpha-rust-mesh programs/hashjob/wasm), so a job array runs on the CPU of every member. OP_JOB
3 * item i (i = the u64 meshd wrote at V_JOB_BASE + arg): the XOR of the first LE u32 of
4 * sha256d(LE8(i * K + j)) for j in 0..K (K = the manifest's param), and the item's job_out record:
5 * the first 16 bytes of sha256d(LE8(i)) at V_OUT + 16 (ticket % 64). Setup ops make test items:
6 * 3 item `arg` fails (R_JOB_FAIL), 4 item `arg` traps, 5 clears both. */
7#include "mesh/abi/ring.h"
8#include "mesh/ref/sha256d.h"
9#include "mesh/rt_wasm.h"
10
11#define V_MAGIC 0x00u
12#define V_JOB_BASE 0x08u
13#define V_FAIL_ITEM 0x10u /* item + 1 (low 32 bits), 0: none */
14#define V_TRAP_ITEM 0x18u
15#define V_ITEMS 0x20u
16#define V_HASHES 0x28u
17#define V_LAST 0x30u
18#define V_OUT 0x100u
19#define OUT_REC 16u
20#define MAGIC 0x4a485348u /* "HSHJ" */
21
22#define OP_FAIL_ITEM 3u
23#define OP_TRAP_ITEM 4u
24#define OP_CLEAR 5u
25
26static void init(const mesh_ctx *ctx) {
27    mesh_view v = mesh_ctx_view(ctx);
28    mesh_view_set_u32(v, V_MAGIC, MAGIC);
29    mesh_view_set_u32(v, V_FAIL_ITEM, 0);
30    mesh_view_set_u32(v, V_TRAP_ITEM, 0);
31}
32
33static void le8(uint64_t x, uint8_t out[8]) {
34    for (int k = 0; k < 8; k++) out[k] = (uint8_t)(x >> (8 * k));
35}
36
37static uint32_t item(const mesh_ctx *ctx, uint32_t arg) {
38    mesh_view v = mesh_ctx_view(ctx);
39    uint64_t i = mesh_view_u64(v, V_JOB_BASE) + arg;
40    if (mesh_view_u32(v, V_FAIL_ITEM) == (uint32_t)i + 1u) {
41        mesh_ctx_count(ctx, 2, 1);
42        return MESH_R_JOB_FAIL;
43    }
44    if (mesh_view_u32(v, V_TRAP_ITEM) == (uint32_t)i + 1u) MESH_TRAP();
45    uint32_t p = mesh_ctx_param(ctx);
46    uint64_t k = p > 1 ? p : 1;
47    uint32_t fold = 0;
48    uint8_t b[8], h[32];
49    for (uint64_t j = 0; j < k; j++) {
50        le8(i * k + j, b);
51        mesh_sha256d(b, 8, h);
52        fold ^= (uint32_t)h[0] | (uint32_t)h[1] << 8 | (uint32_t)h[2] << 16 | (uint32_t)h[3] << 24;
53    }
54    le8(i, b);
55    mesh_sha256d(b, 8, h);
56    mesh_view_write(v, V_OUT + OUT_REC * (mesh_ctx_ticket(ctx) % MESH_PROG_RESULTS), h, OUT_REC);
57    mesh_view_add64(v, V_ITEMS, 1);
58    mesh_view_add64(v, V_HASHES, k);
59    mesh_view_set_u64(v, V_LAST, i);
60    mesh_ctx_count(ctx, 0, 1);
61    uint64_t per = k / 1024;
62    mesh_ctx_count(ctx, 1, (uint32_t)(per > 1 ? per : 1));
63    /* R_JOB_FAIL is reserved: a fold that equals it is reported as R_JOB_FAIL - 1 (fleetcheck does the same). */
64    return fold == MESH_R_JOB_FAIL ? fold - 1u : fold;
65}
66
67static uint32_t task(const mesh_ctx *ctx, uint32_t op, uint32_t arg) {
68    mesh_view v = mesh_ctx_view(ctx);
69    switch (op) {
70    case MESH_OP_JOB: return item(ctx, arg);
71    case OP_FAIL_ITEM: mesh_view_set_u32(v, V_FAIL_ITEM, arg + 1u); return MESH_R_NONE;
72    case OP_TRAP_ITEM: mesh_view_set_u32(v, V_TRAP_ITEM, arg + 1u); return MESH_R_NONE;
73    case OP_CLEAR:
74        mesh_view_set_u32(v, V_FAIL_ITEM, 0);
75        mesh_view_set_u32(v, V_TRAP_ITEM, 0);
76        return MESH_R_NONE;
77    default: return MESH_R_BAD_OP;
78    }
79}
80
81MESH_PROGRAM(init, task)