This commit is contained in:
2026-10-19 15:42:39 -04:00
parent 6d3f470922
commit 4b47386853
218 changed files with 25348 additions and 383 deletions
+25
View File
@@ -0,0 +1,25 @@
[CmdletBinding()]
param(
[string]$BuildDirectory = (Join-Path $PSScriptRoot '../native/build'),
[string]$Generator = '',
[ValidateRange(1, 64)][int]$Jobs = 2,
[switch]$Test
)
$ErrorActionPreference = 'Stop'
$SourceDirectory = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../native'))
$BuildDirectory = [System.IO.Path]::GetFullPath($BuildDirectory)
if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { throw 'CMake 3.24+ is required.' }
if (-not (Get-Command git -ErrorAction SilentlyContinue)) { throw 'Git is required to fetch pinned RandomX.' }
$NativeTests = if ($Test) { 'ON' } else { 'OFF' }
$ConfigureArguments = @('-S', $SourceDirectory, '-B', $BuildDirectory,
'-DCMAKE_BUILD_TYPE=Release', "-DWIKIDECK_RANDOMX_TESTS=$NativeTests")
if ($Generator) { $ConfigureArguments += @('-G', $Generator) }
& cmake @ConfigureArguments
if ($LASTEXITCODE -ne 0) { throw 'RandomX CMake configuration failed.' }
& cmake --build $BuildDirectory --config Release --target wikideck-randomx --parallel $Jobs
if ($LASTEXITCODE -ne 0) { throw 'RandomX native build failed.' }
if ($Test) {
& ctest --test-dir $BuildDirectory -C Release --output-on-failure
if ($LASTEXITCODE -ne 0) { throw 'RandomX known-vector test failed.' }
}
Write-Host "Built native RandomX engine in $BuildDirectory"
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
set -eu
# Usage: sh scripts/build-randomx.sh [--test]; JOBS defaults to a modest two compiler jobs.
tests=OFF
case "${1-}" in
'') ;;
--test) tests=ON; shift ;;
*) printf '%s\n' 'usage: build-randomx.sh [--test]' >&2; exit 2 ;;
esac
[ "$#" -eq 0 ] || { printf '%s\n' 'unexpected argument' >&2; exit 2; }
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
build=${RANDOMX_BUILD_DIR:-"$root/native/build"}
jobs=${JOBS:-2}
case "$jobs" in ''|*[!0-9]*) printf '%s\n' 'JOBS must be 1..64' >&2; exit 2 ;; esac
[ "$jobs" -ge 1 ] && [ "$jobs" -le 64 ] || { printf '%s\n' 'JOBS must be 1..64' >&2; exit 2; }
command -v cmake >/dev/null 2>&1 || { printf '%s\n' 'CMake 3.24+ is required' >&2; exit 1; }
command -v git >/dev/null 2>&1 || { printf '%s\n' 'Git is required' >&2; exit 1; }
cmake -S "$root/native" -B "$build" -DCMAKE_BUILD_TYPE=Release "-DWIKIDECK_RANDOMX_TESTS=$tests"
cmake --build "$build" --config Release --target wikideck-randomx --parallel "$jobs"
if [ "$tests" = ON ]; then ctest --test-dir "$build" -C Release --output-on-failure; fi
printf 'Built native RandomX engine in %s\n' "$build"
+59
View File
@@ -0,0 +1,59 @@
// Explicit opt-in live-network test. Creates disposable wallets and mines three test NFTs.
import assert from 'node:assert/strict';
import { generateKeyPairSync, sign } from 'node:crypto';
import { setTimeout as delay } from 'node:timers/promises';
import { RandomX } from '../server/testnet/randomx.ts';
import { address, CHAIN_ID, miningBlob, mintId, sha256 } from '../server/testnet/consensus.ts';
import { blockClaimMessage, nftTransferMessage, NETWORK, testnetOwnerOf, type MiningTemplate, type TestnetSnapshot } from '../shared/testnet.ts';
if(!process.argv.includes('--consent'))throw new Error('This test mines three blocks with a native CPU worker. Pass --consent explicitly. Disposable NFT rewards are not recoverable.');
const nodes=(process.env.WIKIDECK_SMOKE_NODES??'http://127.0.0.1:3101,http://127.0.0.1:3102,http://127.0.0.1:3103').split(',');
for(const endpoint of nodes)if(!/^http:\/\/127\.0\.0\.1:\d+$/.test(endpoint))throw new Error('Smoke test only accepts explicit loopback test nodes');
async function api(node:string,path:string,body?:unknown){
const r=await fetch(node+path,{method:body?'POST':'GET',headers:body?{'Content-Type':'application/json'}:{},
body:body?JSON.stringify(body):undefined,signal:AbortSignal.timeout(15000),redirect:'error'});
const value=await r.json();if(!r.ok)throw new Error(value.error??`HTTP${r.status}`);return value;
}
const keys=generateKeyPairSync('ec',{namedCurve:'prime256v1'});
const publicKey=keys.publicKey.export({format:'der',type:'spki'}).toString('base64'),owner=address(publicKey);
const receiver=generateKeyPairSync('ec',{namedCurve:'prime256v1'});
const to=address(receiver.publicKey.export({format:'der',type:'spki'}).toString('base64'));
const signed=(m:string)=>sign('sha256',Buffer.from(m),{key:keys.privateKey,dsaEncoding:'ieee-p1363'}).toString('base64');
const engine=new RandomX();
try {
const initial=await api(nodes[0],'/api/state') as TestnetSnapshot;
assert.equal(initial.chainId,CHAIN_ID);
console.log(`Testing ${nodes.length} independent nodes on ${CHAIN_ID}; starting height ${initial.blocks.length}`);
let first='';
for(let count=0;count<3;count++) {
if(count===2){
const tx={network:NETWORK,chainId:CHAIN_ID,cardHash:first,from:owner,to,sequence:0};
await api(nodes[0],'/api/transfer',{...tx,publicKey,signature:signed(nftTransferMessage(tx))});
const pending=await api(nodes[0],'/api/state') as TestnetSnapshot;
assert.equal(testnetOwnerOf(pending,first),owner);
assert.ok(pending.pendingTransfers.some(t=>t.cardHash===first));
}
const template=await api(nodes[0],'/api/mining/template',{owner,publicKey}) as MiningTemplate;
let found;
for(let batch=0;batch<100;batch++){
found=await engine.mine(template.header.key,miningBlob(template.header),template.header.target,32,32);
if(found)break;template.header.nonce+=32;
}
assert.ok(found,'Native proof not found within smoke budget');
template.header.nonce=found.nonce;
const hash=sha256(miningBlob(template.header)),tokenId=mintId(template.header);
await api(nodes[0],'/api/blocks',{...template.header,hash,tokenId,powHash:found.hash,signature:signed(blockClaimMessage(hash)),transactions:template.transactions});
if(count===0)first=tokenId;
console.log(`Native RandomX block #${template.header.height} accepted: ${hash}`);
}
const canonical=await api(nodes[0],'/api/state') as TestnetSnapshot;
const deadline=Date.now()+60000;
for(;;){
const states=await Promise.all(nodes.map(n=>api(n,'/api/state') as Promise<TestnetSnapshot>));
if(states.every(s=>s.tip===canonical.tip&&s.cumulativeWork===canonical.cumulativeWork&&testnetOwnerOf(s,first)===to)){
console.log(`PASS: ${states.length} independent nodes agreed on work ${canonical.cumulativeWork}, tip, NFT issuance and mined transfer.`);break;
}
if(Date.now()>deadline)throw new Error('Peer convergence timeout');
await delay(500);
}
}finally{engine.close();}