Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Build and Pre-release

on:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-22.04-arm
permissions:
contents: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Install System Dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc g++ make cmake git curl clang pkg-config wget

- name: Download Pearl Dependencies
run: |
sudo mkdir -p /root/pearl-rust
TEMP_DIR=$(mktemp -d)
git clone --depth 1 https://github.com/pearl-research-labs/pearl.git "$TEMP_DIR/pearl"
sudo cp -r "$TEMP_DIR/pearl/." /root/pearl-rust/
rm -rf "$TEMP_DIR"
sudo ls -la /root/pearl-rust/

- name: Download and Install Ascend CANN Toolkit
run: |
wget -q https://ascend.devcloud.huaweicloud.com/artifactory/cann-run-mirror/software/legacy/20260422000325096/Ascend-cann-toolkit_9.0.0_linux-aarch64.run
chmod +x Ascend-cann-toolkit_9.0.0_linux-aarch64.run
bash ./Ascend-cann-toolkit_9.0.0_linux-aarch64.run --install --quiet
sudo su -c "
rustup default stable
"

- name: Setup BLAKE3 Vendor Path for Makefile
run: |
sudo mkdir -p /root/.cargo/registry/src/github.com-1ecc6299db9ec823/blake3-1.5.0/c
git clone --depth 1 https://github.com/BLAKE3-team/BLAKE3.git /tmp/blake3_repo
sudo cp -r /tmp/blake3_repo/c/. /root/.cargo/registry/src/github.com-1ecc6299db9ec823/blake3-1.5.0/c/
rm -rf /tmp/blake3_repo

- name: Build Project
run: |
sudo su -c "
source /home/runner/Ascend/cann/set_env.sh
make RANK=128 MBATCH=2
"

- name: Package Build Output
run: |
sudo tar -czvf build-aarch64.tar.gz -C build .

- name: Create Pre-release
uses: softprops/action-gh-release@v2
with:
tag_name: pre-release-${{ github.run_number }}
name: Pre-release Build #${{ github.run_number }}
prerelease: true
files: build-aarch64.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ CC := gcc
# Dev fee (disclosed, open-source): per-mille of submitted shares sent to the dev wallet
# (DEV_FEE_ADDR in src/miner.c). 10 = 1.0%. Build `make DEV_FEE_PERMILLE=0` to disable.
DEV_FEE_PERMILLE ?= 10
CFLAGS := -O3 -march=armv8-a+crypto -DBLAKE3_USE_NEON=1 -DBLAKE3_USE_TBB -DK=$(K) -DRANK=$(RANK) -DMDIM=$(MDIM) -DDEV_FEE_PERMILLE=$(DEV_FEE_PERMILLE) -I$(BLK)
CFLAGS := -O3 -fopenmp -march=armv8-a+crypto -DBLAKE3_USE_NEON=1 -DBLAKE3_USE_TBB -DK=$(K) -DRANK=$(RANK) -DMDIM=$(MDIM) -DDEV_FEE_PERMILLE=$(DEV_FEE_PERMILLE) -I$(BLK)
RPATH := -Wl,-rpath,'$$ORIGIN'
MBATCH ?= 1

Expand Down
29 changes: 20 additions & 9 deletions src/miner.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ extern void pearl_set_bt_slot(const int8_t *bt, int slot) __attribute__((weak));
extern int prep_random(uint64_t seed, int8_t *A, int8_t *B, const uint8_t *key,
int64_t m, int64_t n, int64_t k, int rank,
int8_t *An, int8_t *Btn, int8_t *EAL, int8_t *EBR,
uint8_t *rA, uint8_t *rB, uint8_t *cA, uint8_t *cB, int nt);
uint8_t *rA, uint8_t *rB, uint8_t *cA, uint8_t *cB, int nt, int cert_version);
extern int prep_random_bt(uint64_t seed, int8_t *A, int8_t *B, const uint8_t *key,
int64_t m, int64_t n, int64_t k, int rank,
int8_t *An, int8_t *bt_packed, int8_t *EAL, int8_t *EBR,
uint8_t *rA, uint8_t *rB, uint8_t *cA, uint8_t *cB, int nt);
uint8_t *rA, uint8_t *rB, uint8_t *cA, uint8_t *cB, int nt, int cert_version);
/* reuse-B split — B-side cached per job, A-side regenerated per iter. */
extern int prep_b_side(uint64_t seed, int8_t *B, const uint8_t *key,
int64_t n, int64_t k, int rank,
int8_t *bt_packed, int8_t *EBR, uint8_t *rootB, uint8_t *commitB, int nt);
int8_t *bt_packed, int8_t *EBR, uint8_t *rootB, uint8_t *commitB, int nt, int cert_version);
extern int prep_a_side(uint64_t seed, int8_t *A, const uint8_t *key, const uint8_t *commitB,
int64_t m, int64_t k, int rank,
int8_t *An, int8_t *EAL, uint8_t *rootA, uint8_t *commitA, int nt);
int8_t *An, int8_t *EAL, uint8_t *rootA, uint8_t *commitA, int nt, int cert_version);
extern int scan_full(const int8_t *an, int nstrips, const uint8_t *key, const uint32_t *tgt,
int nbands, int n_hi, int pow_threads, uint32_t *scratch,
int *hs, int *ht);
Expand Down Expand Up @@ -144,6 +144,10 @@ typedef struct {
char job_id[JOBLEN];
double diff;
uint8_t ptarget[32];
int cert_version; /* consensus version captured at prep time, so it always matches
* the roots/commits this bundle was salted with (see bundle_key
* / prep_worker: read once, from the job that keyed this bundle,
* not re-read at submit time). */
int slot; /* this bundle's device B-buffer slot (0/1, = bun[] index) */
} bundle_t;
static void bundle_key(bundle_t *b);
Expand All @@ -165,6 +169,7 @@ static struct {
uint8_t key[32], commitB[32], rootB[32];
char job_id[JOBLEN];
double diff; uint8_t ptarget[32];
int cert_version;
int slot, valid; long since;
} bs;
/* (main thread, between scans) rebuild the B-side iff the job changed or the refresh interval
Expand All @@ -176,13 +181,15 @@ static int ensure_bside(long N, long Kc, int rank, int prep_n) {
int jobchg = !bs.valid || strncmp(bs.job_id, g_job->job_id, JOBLEN - 1);
char jid[JOBLEN]; strncpy(jid, g_job->job_id, JOBLEN - 1); jid[JOBLEN - 1] = 0;
double diff = g_job->difficulty; uint8_t pt[32]; memcpy(pt, g_job->ptarget, 32);
int cert_version = g_job->cert_version;
static uint8_t hdr[HDRLEN]; size_t hl = g_job->header_len; memcpy(hdr, g_job->header, hl);
pthread_mutex_unlock(&job_mu);
if (!(jobchg || (refresh > 0 && bs.since >= refresh))) return 0;
strncpy(bs.job_id, jid, JOBLEN - 1); bs.diff = diff; memcpy(bs.ptarget, pt, 32);
bs.cert_version = cert_version;
hash_key(hdr, hl, (size_t)Kc, (size_t)rank, mp.rows, mp.nrows, mp.cols, mp.ncols, bs.key);
uint64_t seed = ((uint64_t)rand() << 32) ^ (uint64_t)time(0) ^ 0xB5B5ULL;
prep_b_side(seed, bs.B, bs.key, N, Kc, rank, bs.bt, bs.EBR, bs.rootB, bs.commitB, prep_n);
prep_b_side(seed, bs.B, bs.key, N, Kc, rank, bs.bt, bs.EBR, bs.rootB, bs.commitB, prep_n, cert_version);
if (pearl_set_bt_slot) pearl_set_bt_slot(bs.bt, 0); /* single device slot 0 */
else if (pearl_set_b_slot) pearl_set_b_slot(bs.bt, (int)N, 0);
bs.slot = 0; bs.valid = 1; bs.since = 0;
Expand All @@ -197,8 +204,10 @@ static void *prep_worker(void *p) {
uint64_t seed = ((uint64_t)rand() << 32) ^ (uint64_t)time(0);
strncpy(b->job_id, bs.job_id, JOBLEN - 1);
b->diff = bs.diff; memcpy(b->ptarget, bs.ptarget, 32); memcpy(b->key, bs.key, 32);
b->cert_version = bs.cert_version;
prep_a_side(seed, b->A, bs.key, bs.commitB, mp.m, mp.k, (int)mp.rank,
b->An, g_EAL, b->roots[0] /*rootA*/, b->roots[2] /*commitA = PoW key*/, prep_n);
b->An, g_EAL, b->roots[0] /*rootA*/, b->roots[2] /*commitA = PoW key*/, prep_n,
bs.cert_version);
clock_gettime(CLOCK_MONOTONIC, &pb);
g_last_prep_ms = (pb.tv_sec - pa.tv_sec) * 1000 + (pb.tv_nsec - pa.tv_nsec) / 1000000;
return 0;
Expand Down Expand Up @@ -227,11 +236,11 @@ static void *prep_worker(void *p) {
if (pearl_set_bt_slot) {
prep_random_bt(seed, b->A, b->B, b->key, mp.m, mp.n, mp.k, (int)mp.rank,
b->An, b->Btn, b->EAL, b->EBR,
b->roots[0], b->roots[1], b->roots[2], b->roots[3], prep_n);
b->roots[0], b->roots[1], b->roots[2], b->roots[3], prep_n, b->cert_version);
} else {
prep_random(seed, b->A, b->B, b->key, mp.m, mp.n, mp.k, (int)mp.rank,
b->An, b->Btn, b->EAL, b->EBR,
b->roots[0], b->roots[1], b->roots[2], b->roots[3], prep_n);
b->roots[0], b->roots[1], b->roots[2], b->roots[3], prep_n, b->cert_version);
}
clock_gettime(CLOCK_MONOTONIC, &pb);
g_last_prep_ms = (pb.tv_sec - pa.tv_sec) * 1000 + (pb.tv_nsec - pa.tv_nsec) / 1000000;
Expand All @@ -244,6 +253,7 @@ static void bundle_key(bundle_t *b) {
pthread_mutex_lock(&job_mu);
strncpy(b->job_id, g_job->job_id, JOBLEN - 1);
b->diff = g_job->difficulty;
b->cert_version = g_job->cert_version;
memcpy(b->ptarget, g_job->ptarget, 32);
hash_key(g_job->header, g_job->header_len, (size_t)mp.k, (size_t)mp.rank,
mp.rows, mp.nrows, mp.cols, mp.ncols, b->key);
Expand Down Expand Up @@ -391,9 +401,10 @@ int main(int argc, char **argv) {
/* B changed -> cur->An used the old commitB; re-prep cur's A-side to match */
uint64_t s = ((uint64_t)rand() << 32) ^ (uint64_t)time(0) ^ 0xA5A5ULL;
prep_a_side(s, cur->A, bs.key, bs.commitB, mp.m, mp.k, (int)mp.rank,
cur->An, g_EAL, cur->roots[0], cur->roots[2], prep_n);
cur->An, g_EAL, cur->roots[0], cur->roots[2], prep_n, bs.cert_version);
strncpy(cur->job_id, bs.job_id, JOBLEN - 1);
cur->diff = bs.diff; memcpy(cur->ptarget, bs.ptarget, 32); memcpy(cur->key, bs.key, 32);
cur->cert_version = bs.cert_version;
}
bs.since++;
}
Expand Down
2 changes: 2 additions & 0 deletions src/pools/k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static void k1_handle_notify(pool_conn_t *c, const char *line) {
if (jstr(line, "header", hdr, sizeof hdr)) return;
if (jstr(line, "job_id", jid, sizeof jid)) return;
long height = (long)jnum(line, "height", 0);
int cert_version = (int)jnum(line, "cert_version", 1); /* default: legacy, pre-fork pools omit it */
uint8_t ptarget[32]; int have_t = 0;
if (!jstr(line, "target", tgt, sizeof tgt)) {
memset(ptarget, 0, 32);
Expand All @@ -74,6 +75,7 @@ static void k1_handle_notify(pool_conn_t *c, const char *line) {
strncpy(c->job.job_id, jid, JOBLEN - 1);
c->job.header_len = (size_t)hex2bin(hdr, c->job.header, HDRLEN);
c->job.height = height;
c->job.cert_version = cert_version;
if (have_t) { memcpy(c->job.ptarget, ptarget, 32); c->job.have_target = 1; }
c->job.have = 1;
pthread_mutex_unlock(&job_mu);
Expand Down
6 changes: 5 additions & 1 deletion src/pools/kryptex.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,14 @@ static int k_open(pool_conn_t *c, const char *host, int port,
}

static void k_handle_notify(pool_conn_t *c, const char *line) {
/* params is an OBJECT: {header, height, job_id, target} */
/* params is an OBJECT: {header, height, job_id, target[, cert_version]}.
* cert_version is read defensively (defaults to 1) in case this pool adds it later,
* same as k1 -- see docs/salted-seed-fork-upgrade-guide.md upstream. */
char jid[JOBLEN], hdr[2 * HDRLEN], tgt[80];
if (jstr(line, "header", hdr, sizeof hdr)) return;
if (jstr(line, "job_id", jid, sizeof jid)) return;
long height = (long)jnum(line, "height", 0);
int cert_version = (int)jnum(line, "cert_version", 1);
uint8_t ptarget[32]; int have_t = 0;
if (!jstr(line, "target", tgt, sizeof tgt)) {
memset(ptarget, 0, 32);
Expand All @@ -82,6 +85,7 @@ static void k_handle_notify(pool_conn_t *c, const char *line) {
strncpy(c->job.job_id, jid, JOBLEN - 1);
c->job.header_len = (size_t)hex2bin(hdr, c->job.header, HDRLEN);
c->job.height = height;
c->job.cert_version = cert_version;
if (have_t) { memcpy(c->job.ptarget, ptarget, 32); c->job.have_target = 1; }
c->job.have = 1;
pthread_mutex_unlock(&job_mu);
Expand Down
5 changes: 5 additions & 0 deletions src/pools/pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ typedef struct {
uint8_t ptarget[32]; /* pool target (big-endian), for object-notify pools (kryptex) */
int have_target;
long height;
int cert_version; /* certificate/consensus version for this job's noise-seed
* derivation: 1/2 = legacy (unsalted), 3+ = salted (post
* salted-seed fork). Defaults to 1 when a pool omits the
* field (pre-fork pools); read it from mining.notify, never
* hardcode a fork height client-side. */
int have;
} job_t;

Expand Down
1 change: 1 addition & 0 deletions src/pools/stratum.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void pool_conn_init(pool_conn_t *c, const char *tag) {
c->tag = tag;
c->gzip = 0;
c->job.have = 0;
c->job.cert_version = 1; /* legacy default until the first mining.notify sets it */
pthread_mutex_init(&c->send_mu, 0);
}

Expand Down
Loading