Merge pull request #2272 from PR0M3TH3AN/perf/load-test-wasm-signing-11705129069826506892

⚡ Accelerate load test signing with WASM
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-09 13:36:43 -05:00
commit 4e273da0fe
4 files changed
+99 -26

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
import { finalizeEvent as pureFinalize, generateSecretKey, getPublicKey, getEventHash } from "nostr-tools";
import { finalizeEvent as wasmFinalize, setNostrWasm } from "nostr-tools/wasm";
import { initNostrWasm } from "nostr-wasm";
async function main() {
const secretKey = generateSecretKey();
const pubkey = getPublicKey(secretKey);
const ITERATIONS = 1000;
const baseEvent = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [["t", "nostr"], ["t", "benchmark"]],
content: "Hello world, this is a benchmark event.",
pubkey: pubkey,
};
console.log(`Running signing benchmark with ${ITERATIONS} iterations...`);
// 1. Pure JS baseline (finalizeEvent)
{
console.log("Pure JS finalizeEvent...");
const start = performance.now();
for (let i = 0; i < ITERATIONS; i++) {
const event = { ...baseEvent, created_at: baseEvent.created_at + i };
pureFinalize(event, secretKey);
}
const end = performance.now();
const time = end - start;
console.log(`Pure JS time: ${time.toFixed(2)}ms (${(ITERATIONS/time*1000).toFixed(2)} ops/sec)`);
}
// 2. WASM
console.log("Initializing WASM...");
const wasm = await initNostrWasm();
setNostrWasm(wasm);
{
console.log("WASM finalizeEvent...");
const start = performance.now();
for (let i = 0; i < ITERATIONS; i++) {
const event = { ...baseEvent, created_at: baseEvent.created_at + i };
wasmFinalize(event, secretKey);
}
const end = performance.now();
const time = end - start;
console.log(`WASM time: ${time.toFixed(2)}ms (${(ITERATIONS/time*1000).toFixed(2)} ops/sec)`);
}
}
main().catch(console.error);
+25 -24
View File
@@ -23,6 +23,7 @@
"@playwright/test": "^1.58.2",
"fake-indexeddb": "^6.2.5",
"jsdom": "^28.0.0",
"nostr-wasm": "^0.1.0",
"pixelmatch": "^5.3.0",
"playwright": "^1.58.2",
"pngjs": "^7.0.0",
@@ -792,30 +793,6 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/curves": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "1.3.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/curves/node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -3328,6 +3305,30 @@
}
}
},
"node_modules/nostr-tools/node_modules/@noble/curves": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "1.3.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/nostr-tools/node_modules/@noble/curves/node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/nostr-tools/node_modules/@noble/hashes": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
+1
View File
@@ -41,6 +41,7 @@
"@playwright/test": "^1.58.2",
"fake-indexeddb": "^6.2.5",
"jsdom": "^28.0.0",
"nostr-wasm": "^0.1.0",
"pixelmatch": "^5.3.0",
"playwright": "^1.58.2",
"pngjs": "^7.0.0",
+21 -2
View File
@@ -1,11 +1,16 @@
import { WebSocket } from 'ws';
import { finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools';
import { finalizeEvent as pureFinalize, generateSecretKey, getPublicKey as pureGetPublicKey } from 'nostr-tools';
import { finalizeEvent as wasmFinalize, getPublicKey as wasmGetPublicKey, setNostrWasm } from 'nostr-tools/wasm';
import { initNostrWasm } from 'nostr-wasm';
import { startRelay } from './simple-relay.mjs';
import { buildViewEvent, buildVideoPostEvent } from '../../js/nostrEventSchemas.js';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
let finalizeEvent = pureFinalize;
let getPublicKey = pureGetPublicKey;
// --- Polyfills and Environment Setup ---
if (typeof global.window === 'undefined') {
global.window = {};
@@ -223,6 +228,17 @@ class LoadClient {
async function main() {
console.log(`Starting load test with config:`, config);
try {
console.log('Initializing WASM crypto...');
const wasm = await initNostrWasm();
setNostrWasm(wasm);
finalizeEvent = wasmFinalize;
getPublicKey = wasmGetPublicKey;
console.log('WASM crypto initialized successfully.');
} catch (error) {
console.warn('Failed to initialize WASM crypto, falling back to pure JS:', error);
}
let relayServer;
let relayUrl = config.relay;
@@ -358,11 +374,13 @@ function generateReport() {
report.topHotFunctions.push({
function: "finalizeEvent (client signing)",
avgTime: `${avgSignTime.toFixed(2)}ms`,
impact: avgSignTime > 10 ? "High CPU usage" : "Moderate CPU usage"
impact: avgSignTime > 10 ? "High CPU usage" : "Low/Moderate CPU usage"
});
if (avgSignTime > 10) {
report.proposedRemediation.push("Use optimized crypto library (e.g. secp256k1-wasm) or offload signing to a worker/signer.");
} else {
report.proposedRemediation.push("Signing speed is good (<10ms). Focus on network I/O.");
}
if (p99 > 1000) {
@@ -393,6 +411,7 @@ function generateReport() {
console.log(` Latency p50: ${p50}ms`);
console.log(` Latency p95: ${p95}ms`);
console.log(` Errors: ${stats.errors}`);
console.log(` Avg Signing Time: ${avgSignTime.toFixed(2)}ms`);
}
main().catch(console.error);