WASM: PoW

This commit is contained in:
Kieran 2023-09-24 21:28:39 +01:00
parent 9f731da5be
commit 6e7a28a42b
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
19 changed files with 1146 additions and 52 deletions

View File

@ -21,7 +21,7 @@ import Note from "Element/Note";
import { ClipboardEventHandler } from "react";
import useLogin from "Hooks/useLogin";
import { System } from "index";
import { System, WasmPowWorker } from "index";
import AsyncButton from "Element/AsyncButton";
import { AsyncIcon } from "Element/AsyncIcon";
import { fetchNip05Pubkey } from "@snort/shared";
@ -30,9 +30,9 @@ import { useNoteCreator } from "State/NoteCreator";
export function NoteCreator() {
const { formatMessage } = useIntl();
const publisher = useEventPublisher();
const uploader = useFileUpload();
const login = useLogin(s => ({ relays: s.relays, publicKey: s.publicKey }));
const login = useLogin(s => ({ relays: s.relays, publicKey: s.publicKey, pow: s.preferences.pow }));
const publisher = login.pow ? useEventPublisher()?.pow(login.pow, new WasmPowWorker()) : useEventPublisher();
const note = useNoteCreator();
const relays = login.relays;

View File

@ -2,13 +2,14 @@ import useLogin from "Hooks/useLogin";
import "./PinPrompt.css";
import { ReactNode, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import useEventPublisher from "Hooks/useEventPublisher";
import { LoginStore, createPublisher, sessionNeedsPin } from "Login";
import { unwrap } from "@snort/shared";
import { EventPublisher, InvalidPinError, PinEncrypted, PinEncryptedPayload } from "@snort/system";
import { DefaultPowWorker } from "index";
import useEventPublisher from "Hooks/useEventPublisher";
import { LoginStore, createPublisher, sessionNeedsPin } from "Login";
import Modal from "./Modal";
import AsyncButton from "./AsyncButton";
import { WasmPowWorker } from "index";
export function PinPrompt({
onResult,
@ -91,7 +92,7 @@ export function LoginUnlock() {
const pub = EventPublisher.privateKey(k);
if (login.preferences.pow) {
pub.pow(login.preferences.pow, DefaultPowWorker);
pub.pow(login.preferences.pow, new WasmPowWorker());
}
LoginStore.setPublisher(login.id, pub);
LoginStore.updateSession({
@ -108,7 +109,7 @@ export function LoginUnlock() {
const pub = createPublisher(login, key);
if (pub) {
if (login.preferences.pow) {
pub.pow(login.preferences.pow, DefaultPowWorker);
pub.pow(login.preferences.pow, new WasmPowWorker());
}
LoginStore.setPublisher(login.id, pub);
LoginStore.updateSession({

View File

@ -1,6 +1,5 @@
import useLogin from "Hooks/useLogin";
import { LoginStore, createPublisher, sessionNeedsPin } from "Login";
import { DefaultPowWorker } from "index";
export default function useEventPublisher() {
const login = useLogin();
@ -10,12 +9,8 @@ export default function useEventPublisher() {
if (login.publicKey && !existing && !sessionNeedsPin(login)) {
existing = createPublisher(login);
if (existing) {
if (login.preferences.pow) {
existing.pow(login.preferences.pow, DefaultPowWorker);
}
LoginStore.setPublisher(login.id, existing);
}
}
return existing;
}

View File

@ -1,6 +1,6 @@
import { bytesToHex } from "@noble/hashes/utils";
import { DefaultQueryOptimizer, FlatReqFilter, QueryOptimizer, ReqFilter } from "@snort/system";
import { compress, expand_filter, flat_merge, get_diff, default as wasmInit } from "@snort/system-wasm";
import { DefaultQueryOptimizer, EventExt, FlatReqFilter, PowMiner, QueryOptimizer, ReqFilter } from "@snort/system";
import { compress, expand_filter, flat_merge, get_diff, pow, default as wasmInit } from "@snort/system-wasm";
import WasmPath from "@snort/system-wasm/pkg/system_wasm_bg.wasm";
import { Bench } from "tinybench";
@ -90,15 +90,35 @@ const testCompress = (q: QueryOptimizer) => {
const wasmSuite = new Bench({ time: 1_000 });
const suite = new Bench({ time: 1_000 });
const addTests = (s: Bench, q: QueryOptimizer) => {
const addTests = (s: Bench, q: QueryOptimizer, p: PowMiner) => {
s.add("expand", () => testExpand(q));
s.add("get_diff", () => testGetDiff(q));
s.add("flat_merge", () => testFlatMerge(q));
s.add("compress", () => testCompress(q));
s.add("pow", () => {
const ev = {
id: "",
kind: 1,
created_at: 1234567,
pubkey: "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed",
content: "test",
sig: "",
tags: [],
};
p.minePow(ev, 12);
});
};
addTests(suite, DefaultQueryOptimizer);
addTests(wasmSuite, WasmQueryOptimizer);
addTests(suite, DefaultQueryOptimizer, {
minePow(ev, target) {
return Promise.resolve(EventExt.minePow(ev, target));
},
});
addTests(wasmSuite, WasmQueryOptimizer, {
minePow(ev, target) {
return Promise.resolve(pow(ev, target));
},
});
const runAll = async () => {
await wasmInit(WasmPath);
@ -106,9 +126,15 @@ const runAll = async () => {
console.log("DefaultQueryOptimizer");
await suite.run();
console.table(suite.table());
const p0 = document.createElement("pre");
p0.innerText = JSON.stringify(suite.table(), undefined, " ");
document.body.appendChild(p0);
console.log("WasmQueryOptimizer");
await wasmSuite.run();
console.table(wasmSuite.table());
const p1 = document.createElement("pre");
p1.innerText = JSON.stringify(wasmSuite.table(), undefined, " ");
document.body.appendChild(p1);
};
runAll().catch(console.error);

View File

@ -3,7 +3,7 @@ import { EventKind, NostrPrefix, encodeTLVEntries, TLVEntryType, TLVEntry, decod
import { GiftWrapCache } from "Cache/GiftWrapCache";
import { UnwrappedGift } from "Db";
import { Chat, ChatSystem, ChatType, lastReadInChat } from "chat";
import { DefaultPowWorker } from "index";
import { WasmPowWorker } from "index";
export class Nip24ChatSystem extends ExternalStore<Array<Chat>> implements ChatSystem {
#cache: GiftWrapCache;
@ -105,7 +105,9 @@ export class Nip24ChatSystem extends ExternalStore<Array<Chat>> implements ChatS
const recvSealedN = pub.giftWrap(await pub.sealRumor(gossip, pt.id), pt.id, powTarget);
messages.push(recvSealedN);
}
messages.push(pub.giftWrap(await pub.sealRumor(gossip, pub.pubKey), pub.pubKey, powTarget, DefaultPowWorker));
messages.push(
pub.giftWrap(await pub.sealRumor(gossip, pub.pubKey), pub.pubKey, powTarget, new WasmPowWorker()),
);
return await Promise.all(messages);
},
sendMessage: (ev, system) => {

View File

@ -2,13 +2,21 @@ import "./index.css";
import "@szhsin/react-menu/dist/index.css";
import "./fonts/inter.css";
import { compress, expand_filter, flat_merge, get_diff, default as wasmInit } from "@snort/system-wasm";
import { compress, expand_filter, flat_merge, get_diff, pow, default as wasmInit } from "@snort/system-wasm";
import WasmPath from "@snort/system-wasm/pkg/system_wasm_bg.wasm";
import { StrictMode } from "react";
import * as ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { NostrSystem, ProfileLoaderService, PowWorker, QueryOptimizer, FlatReqFilter, ReqFilter } from "@snort/system";
import {
NostrSystem,
ProfileLoaderService,
QueryOptimizer,
FlatReqFilter,
ReqFilter,
PowMiner,
NostrEvent,
} from "@snort/system";
import { SnortContext } from "@snort/system-react";
import * as serviceWorkerRegistration from "serviceWorkerRegistration";
@ -53,6 +61,13 @@ const WasmQueryOptimizer = {
},
} as QueryOptimizer;
export class WasmPowWorker implements PowMiner {
minePow(ev: NostrEvent, target: number): Promise<NostrEvent> {
const res = pow(ev, target);
return Promise.resolve(res);
}
}
/**
* Singleton nostr system
*/
@ -75,11 +90,6 @@ export const System = new NostrSystem({
*/
export const ProfileLoader = new ProfileLoaderService(System, UserCache);
/**
* Singleton POW worker
*/
export const DefaultPowWorker = new PowWorker("/pow.js");
serviceWorkerRegistration.register();
async function initSite() {

View File

@ -23,24 +23,77 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
[[package]]
name = "argon2"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ba4cac0a46bc1d2912652a751c47f2a9f3a7fe89bcae2275d418f5270402f9"
dependencies = [
"base64ct",
"blake2",
"cpufeatures",
"password-hash",
]
[[package]]
name = "async-trait"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cast"
version = "0.3.0"
@ -124,6 +177,15 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "cpufeatures"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
[[package]]
name = "criterion"
version = "0.5.1"
@ -203,6 +265,27 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "either"
version = "1.9.0"
@ -230,6 +313,16 @@ dependencies = [
"libc",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.10"
@ -253,6 +346,12 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "is-terminal"
version = "0.4.9"
@ -361,6 +460,17 @@ version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "plotters"
version = "0.3.5"
@ -576,6 +686,35 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha256"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386"
dependencies = [
"async-trait",
"bytes",
"hex",
"sha2",
]
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.31"
@ -591,12 +730,16 @@ dependencies = [
name = "system-wasm"
version = "0.1.0"
dependencies = [
"argon2",
"console_error_panic_hook",
"criterion",
"hex",
"itertools 0.11.0",
"rand",
"serde",
"serde-wasm-bindgen",
"serde_json",
"sha256",
"wasm-bindgen",
"wasm-bindgen-test",
]
@ -611,12 +754,24 @@ dependencies = [
"serde_json",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.4.0"

View File

@ -8,9 +8,13 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
argon2 = "0.5.2"
console_error_panic_hook = "0.1.7"
hex = { version = "0.4.3", features = [], default-features = false }
itertools = "0.11.0"
serde = { version = "1.0.188", features = ["derive"] }
serde = { version = "1.0.188", features = ["derive"], default-features = false }
serde-wasm-bindgen = "0.5.0"
sha256 = { version = "1.4.0", features = [], default-features = false }
wasm-bindgen = "0.2.87"
[dev-dependencies]
@ -21,4 +25,11 @@ criterion = { version = "0.5" }
[[bench]]
name = "basic"
harness = false
harness = false
[profile.release]
opt-level = 3
lto = true
[package.metadata.wasm-pack.profile.release]
wasm-opt = ["-O3"]

View File

@ -1,8 +1,9 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rand::prelude::*;
use std::collections::HashSet;
use system_query::diff::diff_filter;
use system_query::filter::{FlatReqFilter, ReqFilter};
use system_wasm::diff::diff_filter;
use system_wasm::filter::{FlatReqFilter, ReqFilter};
use system_wasm::{Event, pow};
fn random_pubkey(rng: &mut ThreadRng) -> String {
let mut bytes = [0u8; 32];
@ -63,6 +64,20 @@ fn criterion_benchmark(c: &mut Criterion) {
let _ = diff_filter(&prev, &next);
})
});
c.bench_function("pow", |b| {
b.iter(|| {
let mut ev = Event {
id: None,
kind: 1,
created_at: 1234567,
pubkey: "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed".to_string(),
content: "test".to_owned(),
sig: None,
tags: vec![],
};
pow::pow(&mut ev, 12);
})
});
}
criterion_group!(benches, criterion_benchmark);

View File

@ -5,7 +5,7 @@
"author": "Kieran",
"license": "MIT",
"scripts": {
"build": "wasm-pack build -t web -s snort && rm -f pkg/.gitignore"
"build": "wasm-pack build --release -t web -s snort && rm -f pkg/.gitignore"
},
"files": [
"pkg/system_wasm_bg.wasm",

View File

@ -27,6 +27,18 @@ export function flat_merge(val: any): any;
* @returns {any}
*/
export function compress(val: any): any;
/**
* @param {any} val
* @param {any} target
* @returns {any}
*/
export function pow(val: any, target: any): any;
/**
* @param {any} password
* @param {any} salt
* @returns {any}
*/
export function argon2(password: any, salt: any): any;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
@ -37,10 +49,13 @@ export interface InitOutput {
readonly get_diff: (a: number, b: number, c: number) => void;
readonly flat_merge: (a: number, b: number) => void;
readonly compress: (a: number, b: number) => void;
readonly pow: (a: number, b: number, c: number) => void;
readonly argon2: (a: number, b: number, c: number) => void;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_exn_store: (a: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
}
export type SyncInitInput = BufferSource | WebAssembly.Module;

View File

@ -108,6 +108,15 @@ function getInt32Memory0() {
return cachedInt32Memory0;
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
const cachedTextDecoder =
typeof TextDecoder !== "undefined"
? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true })
@ -126,15 +135,6 @@ function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
let cachedFloat64Memory0 = null;
function getFloat64Memory0() {
@ -144,6 +144,15 @@ function getFloat64Memory0() {
return cachedFloat64Memory0;
}
let cachedBigInt64Memory0 = null;
function getBigInt64Memory0() {
if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) {
cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer);
}
return cachedBigInt64Memory0;
}
function debugString(val) {
// primitive types
const type = typeof val;
@ -310,6 +319,48 @@ export function compress(val) {
}
}
/**
* @param {any} val
* @param {any} target
* @returns {any}
*/
export function pow(val, target) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.pow(retptr, addHeapObject(val), addHeapObject(target));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} password
* @param {any} salt
* @returns {any}
*/
export function argon2(password, salt) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.argon2(retptr, addHeapObject(password), addHeapObject(salt));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
function handleError(f, args) {
try {
return f.apply(this, args);
@ -375,6 +426,18 @@ function __wbg_get_imports() {
const ret = getObject(arg0) in getObject(arg1);
return ret;
};
imports.wbg.__wbindgen_is_bigint = function (arg0) {
const ret = typeof getObject(arg0) === "bigint";
return ret;
};
imports.wbg.__wbindgen_bigint_from_u64 = function (arg0) {
const ret = BigInt.asUintN(64, arg0);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_jsval_eq = function (arg0, arg1) {
const ret = getObject(arg0) === getObject(arg1);
return ret;
};
imports.wbg.__wbindgen_error_new = function (arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
@ -513,6 +576,34 @@ function __wbg_get_imports() {
const ret = result;
return ret;
};
imports.wbg.__wbg_new_abda76e883ba8a5f = function () {
const ret = new Error();
return addHeapObject(ret);
};
imports.wbg.__wbg_stack_658279fe44541cf6 = function (arg0, arg1) {
const ret = getObject(arg1).stack;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_error_f851667af71bcfc6 = function (arg0, arg1) {
let deferred0_0;
let deferred0_1;
try {
deferred0_0 = arg0;
deferred0_1 = arg1;
console.error(getStringFromWasm0(arg0, arg1));
} finally {
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
}
};
imports.wbg.__wbindgen_bigint_get_as_i64 = function (arg0, arg1) {
const v = getObject(arg1);
const ret = typeof v === "bigint" ? v : undefined;
getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
};
imports.wbg.__wbindgen_debug_string = function (arg0, arg1) {
const ret = debugString(getObject(arg1));
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -536,6 +627,7 @@ function __wbg_init_memory(imports, maybe_memory) {}
function __wbg_finalize_init(instance, module) {
wasm = instance.exports;
__wbg_init.__wbindgen_wasm_module = module;
cachedBigInt64Memory0 = null;
cachedFloat64Memory0 = null;
cachedInt32Memory0 = null;
cachedUint8Memory0 = null;

View File

@ -0,0 +1,622 @@
let wasm;
export function __wbg_set_wasm(val) {
wasm = val;
}
const heap = new Array(128).fill(undefined);
heap.push(undefined, null, true, false);
function getObject(idx) {
return heap[idx];
}
let heap_next = heap.length;
function dropObject(idx) {
if (idx < 132) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
let WASM_VECTOR_LEN = 0;
let cachedUint8Memory0 = null;
function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
}
const lTextEncoder = typeof TextEncoder === "undefined" ? (0, module.require)("util").TextEncoder : TextEncoder;
let cachedTextEncoder = new lTextEncoder("utf-8");
const encodeString =
typeof cachedTextEncoder.encodeInto === "function"
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length,
};
};
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8Memory0()
.subarray(ptr, ptr + buf.length)
.set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7f) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0;
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function isLikeNone(x) {
return x === undefined || x === null;
}
let cachedInt32Memory0 = null;
function getInt32Memory0() {
if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachedInt32Memory0;
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
const lTextDecoder = typeof TextDecoder === "undefined" ? (0, module.require)("util").TextDecoder : TextDecoder;
let cachedTextDecoder = new lTextDecoder("utf-8", { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
let cachedFloat64Memory0 = null;
function getFloat64Memory0() {
if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) {
cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer);
}
return cachedFloat64Memory0;
}
let cachedBigInt64Memory0 = null;
function getBigInt64Memory0() {
if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) {
cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer);
}
return cachedBigInt64Memory0;
}
function debugString(val) {
// primitive types
const type = typeof val;
if (type == "number" || type == "boolean" || val == null) {
return `${val}`;
}
if (type == "string") {
return `"${val}"`;
}
if (type == "symbol") {
const description = val.description;
if (description == null) {
return "Symbol";
} else {
return `Symbol(${description})`;
}
}
if (type == "function") {
const name = val.name;
if (typeof name == "string" && name.length > 0) {
return `Function(${name})`;
} else {
return "Function";
}
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = "[";
if (length > 0) {
debug += debugString(val[0]);
}
for (let i = 1; i < length; i++) {
debug += ", " + debugString(val[i]);
}
debug += "]";
return debug;
}
// Test for built-in
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
let className;
if (builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == "Object") {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return "Object(" + JSON.stringify(val) + ")";
} catch (_) {
return "Object";
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
/**
* @param {any} prev
* @param {any} next
* @returns {any}
*/
export function diff_filters(prev, next) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.diff_filters(retptr, addHeapObject(prev), addHeapObject(next));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} val
* @returns {any}
*/
export function expand_filter(val) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.expand_filter(retptr, addHeapObject(val));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} prev
* @param {any} next
* @returns {any}
*/
export function get_diff(prev, next) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.get_diff(retptr, addHeapObject(prev), addHeapObject(next));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} val
* @returns {any}
*/
export function flat_merge(val) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.flat_merge(retptr, addHeapObject(val));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} val
* @returns {any}
*/
export function compress(val) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.compress(retptr, addHeapObject(val));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} val
* @param {any} target
* @returns {any}
*/
export function pow(val, target) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.pow(retptr, addHeapObject(val), addHeapObject(target));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
/**
* @param {any} password
* @param {any} salt
* @returns {any}
*/
export function argon2(password, salt) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.argon2(retptr, addHeapObject(password), addHeapObject(salt));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var r2 = getInt32Memory0()[retptr / 4 + 2];
if (r2) {
throw takeObject(r1);
}
return takeObject(r0);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
function handleError(f, args) {
try {
return f.apply(this, args);
} catch (e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
}
export function __wbindgen_object_drop_ref(arg0) {
takeObject(arg0);
}
export function __wbindgen_string_get(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof obj === "string" ? obj : undefined;
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
}
export function __wbindgen_is_object(arg0) {
const val = getObject(arg0);
const ret = typeof val === "object" && val !== null;
return ret;
}
export function __wbindgen_is_undefined(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
}
export function __wbindgen_in(arg0, arg1) {
const ret = getObject(arg0) in getObject(arg1);
return ret;
}
export function __wbindgen_is_bigint(arg0) {
const ret = typeof getObject(arg0) === "bigint";
return ret;
}
export function __wbindgen_bigint_from_u64(arg0) {
const ret = BigInt.asUintN(64, arg0);
return addHeapObject(ret);
}
export function __wbindgen_jsval_eq(arg0, arg1) {
const ret = getObject(arg0) === getObject(arg1);
return ret;
}
export function __wbindgen_error_new(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
}
export function __wbindgen_object_clone_ref(arg0) {
const ret = getObject(arg0);
return addHeapObject(ret);
}
export function __wbindgen_jsval_loose_eq(arg0, arg1) {
const ret = getObject(arg0) == getObject(arg1);
return ret;
}
export function __wbindgen_boolean_get(arg0) {
const v = getObject(arg0);
const ret = typeof v === "boolean" ? (v ? 1 : 0) : 2;
return ret;
}
export function __wbindgen_number_get(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof obj === "number" ? obj : undefined;
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
}
export function __wbindgen_number_new(arg0) {
const ret = arg0;
return addHeapObject(ret);
}
export function __wbindgen_string_new(arg0, arg1) {
const ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
}
export function __wbg_getwithrefkey_5e6d9547403deab8(arg0, arg1) {
const ret = getObject(arg0)[getObject(arg1)];
return addHeapObject(ret);
}
export function __wbg_set_841ac57cff3d672b(arg0, arg1, arg2) {
getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
}
export function __wbg_get_44be0491f933a435(arg0, arg1) {
const ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret);
}
export function __wbg_length_fff51ee6522a1a18(arg0) {
const ret = getObject(arg0).length;
return ret;
}
export function __wbg_new_898a68150f225f2e() {
const ret = new Array();
return addHeapObject(ret);
}
export function __wbindgen_is_function(arg0) {
const ret = typeof getObject(arg0) === "function";
return ret;
}
export function __wbg_next_526fc47e980da008(arg0) {
const ret = getObject(arg0).next;
return addHeapObject(ret);
}
export function __wbg_next_ddb3312ca1c4e32a() {
return handleError(function (arg0) {
const ret = getObject(arg0).next();
return addHeapObject(ret);
}, arguments);
}
export function __wbg_done_5c1f01fb660d73b5(arg0) {
const ret = getObject(arg0).done;
return ret;
}
export function __wbg_value_1695675138684bd5(arg0) {
const ret = getObject(arg0).value;
return addHeapObject(ret);
}
export function __wbg_iterator_97f0c81209c6c35a() {
const ret = Symbol.iterator;
return addHeapObject(ret);
}
export function __wbg_get_97b561fb56f034b5() {
return handleError(function (arg0, arg1) {
const ret = Reflect.get(getObject(arg0), getObject(arg1));
return addHeapObject(ret);
}, arguments);
}
export function __wbg_call_cb65541d95d71282() {
return handleError(function (arg0, arg1) {
const ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret);
}, arguments);
}
export function __wbg_new_b51585de1b234aff() {
const ret = new Object();
return addHeapObject(ret);
}
export function __wbg_set_502d29070ea18557(arg0, arg1, arg2) {
getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
}
export function __wbg_isArray_4c24b343cb13cfb1(arg0) {
const ret = Array.isArray(getObject(arg0));
return ret;
}
export function __wbg_instanceof_ArrayBuffer_39ac22089b74fddb(arg0) {
let result;
try {
result = getObject(arg0) instanceof ArrayBuffer;
} catch {
result = false;
}
const ret = result;
return ret;
}
export function __wbg_isSafeInteger_bb8e18dd21c97288(arg0) {
const ret = Number.isSafeInteger(getObject(arg0));
return ret;
}
export function __wbg_buffer_085ec1f694018c4f(arg0) {
const ret = getObject(arg0).buffer;
return addHeapObject(ret);
}
export function __wbg_new_8125e318e6245eed(arg0) {
const ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
}
export function __wbg_set_5cf90238115182c3(arg0, arg1, arg2) {
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
}
export function __wbg_length_72e2208bbc0efc61(arg0) {
const ret = getObject(arg0).length;
return ret;
}
export function __wbg_instanceof_Uint8Array_d8d9cb2b8e8ac1d4(arg0) {
let result;
try {
result = getObject(arg0) instanceof Uint8Array;
} catch {
result = false;
}
const ret = result;
return ret;
}
export function __wbg_new_abda76e883ba8a5f() {
const ret = new Error();
return addHeapObject(ret);
}
export function __wbg_stack_658279fe44541cf6(arg0, arg1) {
const ret = getObject(arg1).stack;
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
}
export function __wbg_error_f851667af71bcfc6(arg0, arg1) {
let deferred0_0;
let deferred0_1;
try {
deferred0_0 = arg0;
deferred0_1 = arg1;
console.error(getStringFromWasm0(arg0, arg1));
} finally {
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
}
}
export function __wbindgen_bigint_get_as_i64(arg0, arg1) {
const v = getObject(arg1);
const ret = typeof v === "bigint" ? v : undefined;
getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
}
export function __wbindgen_debug_string(arg0, arg1) {
const ret = debugString(getObject(arg1));
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
}
export function __wbindgen_throw(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
}
export function __wbindgen_memory() {
const ret = wasm.memory;
return addHeapObject(ret);
}

View File

@ -6,7 +6,10 @@ export function expand_filter(a: number, b: number): void;
export function get_diff(a: number, b: number, c: number): void;
export function flat_merge(a: number, b: number): void;
export function compress(a: number, b: number): void;
export function pow(a: number, b: number, c: number): void;
export function argon2(a: number, b: number, c: number): void;
export function __wbindgen_malloc(a: number, b: number): number;
export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number;
export function __wbindgen_add_to_stack_pointer(a: number): number;
export function __wbindgen_exn_store(a: number): void;
export function __wbindgen_free(a: number, b: number, c: number): void;

View File

@ -1,12 +1,31 @@
extern crate console_error_panic_hook;
use argon2::{Argon2};
use serde::{Deserialize, Serialize};
use crate::filter::{FlatReqFilter, ReqFilter};
use wasm_bindgen::prelude::*;
pub mod diff;
pub mod filter;
pub mod merge;
pub mod pow;
#[derive(PartialEq, Clone, Serialize, Deserialize)]
pub struct Event {
#[serde(rename = "id", skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub kind: i32,
pub created_at: u64,
pub pubkey: String,
pub content: String,
#[serde(rename = "sig", skip_serializing_if = "Option::is_none")]
pub sig: Option<String>,
pub tags: Vec<Vec<String>>,
}
#[wasm_bindgen]
pub fn diff_filters(prev: JsValue, next: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let prev_parsed: Vec<FlatReqFilter> = serde_wasm_bindgen::from_value(prev)?;
let next_parsed: Vec<FlatReqFilter> = serde_wasm_bindgen::from_value(next)?;
let result = diff::diff_filter(&prev_parsed, &next_parsed);
@ -15,6 +34,7 @@ pub fn diff_filters(prev: JsValue, next: JsValue) -> Result<JsValue, JsValue> {
#[wasm_bindgen]
pub fn expand_filter(val: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let parsed: ReqFilter = serde_wasm_bindgen::from_value(val)?;
let result: Vec<FlatReqFilter> = (&parsed).into();
Ok(serde_wasm_bindgen::to_value(&result)?)
@ -22,6 +42,7 @@ pub fn expand_filter(val: JsValue) -> Result<JsValue, JsValue> {
#[wasm_bindgen]
pub fn get_diff(prev: JsValue, next: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let prev_parsed: Vec<ReqFilter> = serde_wasm_bindgen::from_value(prev)?;
let next_parsed: Vec<ReqFilter> = serde_wasm_bindgen::from_value(next)?;
let expanded_prev: Vec<FlatReqFilter> = prev_parsed
@ -44,6 +65,7 @@ pub fn get_diff(prev: JsValue, next: JsValue) -> Result<JsValue, JsValue> {
#[wasm_bindgen]
pub fn flat_merge(val: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let val_parsed: Vec<FlatReqFilter> = serde_wasm_bindgen::from_value(val)?;
let result = merge::merge::<FlatReqFilter, ReqFilter>(val_parsed.iter().collect());
Ok(serde_wasm_bindgen::to_value(&result)?)
@ -51,11 +73,31 @@ pub fn flat_merge(val: JsValue) -> Result<JsValue, JsValue> {
#[wasm_bindgen]
pub fn compress(val: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let val_parsed: Vec<ReqFilter> = serde_wasm_bindgen::from_value(val)?;
let result = merge::merge::<ReqFilter, ReqFilter>(val_parsed.iter().collect());
Ok(serde_wasm_bindgen::to_value(&result)?)
}
#[wasm_bindgen]
pub fn pow(val: JsValue, target: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let mut val_parsed: Event = serde_wasm_bindgen::from_value(val)?;
let target_parsed: u8 = serde_wasm_bindgen::from_value(target)?;
pow::pow(&mut val_parsed, target_parsed);
Ok(serde_wasm_bindgen::to_value(&val_parsed)?)
}
#[wasm_bindgen]
pub fn argon2(password: JsValue, salt: JsValue) -> Result<JsValue, JsValue> {
console_error_panic_hook::set_once();
let password_parsed: String = serde_wasm_bindgen::from_value(password)?;
let salt_parsed: String = serde_wasm_bindgen::from_value(salt)?;
let mut key = [0u8; 32];
Argon2::default().hash_password_into(password_parsed.as_bytes(), salt_parsed.as_bytes(), &mut key).expect("Failed to generate key");
Ok(serde_wasm_bindgen::to_value(&hex::encode(key))?)
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -0,0 +1,111 @@
use crate::Event;
pub fn pow(ev: &mut Event, target: u8) {
let mut ctr = 0u32;
let mut nonce_tag_idx = ev.tags.iter().position(|x| x[0] == "nonce");
if nonce_tag_idx.is_none() {
nonce_tag_idx = Some(ev.tags.len());
ev.tags.push(vec!["nonce".to_owned(), ctr.to_string(), target.to_string()]);
}
loop {
ev.tags[nonce_tag_idx.unwrap()][1] = ctr.to_string();
let new_id = make_id(ev);
if count_leading_zeros(&new_id) >= target {
ev.id = Some(new_id);
break;
}
ctr += 1;
}
}
fn count_leading_zeros(str: &String) -> u8 {
let mut count = 0;
for x in hex::decode(str).unwrap() {
if x == 0u8 {
count += 8;
} else {
count += x.leading_zeros();
break;
}
}
count as u8
}
fn make_id(ev: &Event) -> String {
let mut v = "[0,\"".to_owned();
v.push_str(&ev.pubkey);
v.push_str("\",");
v.push_str(&ev.created_at.to_string());
v.push(',');
v.push_str(&ev.kind.to_string());
v.push_str(",[");
v.push_str(ev.tags.iter().map(|x| {
let mut y = "[".to_owned();
y.push_str(x.iter().map(|z| ["\"", z, "\""].join("")).collect::<Vec<String>>().join(",").as_str());
y.push(']');
y
}).collect::<Vec<String>>().join(",").as_str());
v.push_str("],\"");
v.push_str(&ev.content);
v.push_str("\"]");
sha256::digest(v)
}
#[cfg(test)]
mod tests {
use serde::Deserialize;
use serde_json::json;
use crate::Event;
#[test]
fn make_id() {
let ev = Event::deserialize(json!({
"content": "Oh i think it doesnt work until you reload",
"created_at": 1695568849,
"id": "0000051bca8ee62220b34827358dca69284734a2e7420f3c4b814901a531c767",
"kind": 1,
"pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed",
"sig": "0c18bfcde49fd42c7faf93b3ecd7caf10f0414c9ee3234fca96ea0bbb1a805cb2767fc067dc1a743420c499b34c232e19b73beb2f1fe47c18a2856c67bdef983",
"tags": [
[
"e",
"ad17146f086345a12583b537daabdf49ccc5cd09e2c0b4816c835f397b693e6b",
"wss://nos.lol/",
"root"
],
[
"e",
"72759bf1f525e9715f4e6d22381f53dc4d2ab47d7aaac11340e7fced13e10b11",
"wss://nos.lol/",
"reply"
],
[
"p",
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed"
],
[
"p",
"1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411"
],
[
"nonce",
"7403",
"18"
]
]
})).ok().unwrap();
assert_eq!(super::make_id(&ev), ev.id.unwrap())
}
#[test]
fn count_zeros() {
assert_eq!(10u8.leading_zeros(), 4);
assert_eq!(super::count_leading_zeros(&"00".to_owned()), 8);
assert_eq!(super::count_leading_zeros(&"0000051bca8ee62220b34827358dca69284734a2e7420f3c4b814901a531c767".to_owned()), 21)
}
}

View File

@ -71,11 +71,13 @@ export class EventPublisher {
}
/**
* Apply POW to every event
* Create a copy of this publisher with PoW
*/
pow(target: number, miner?: PowMiner) {
this.#pow = target;
this.#miner = miner;
const ret = new EventPublisher(this.#signer, this.#pubKey);
ret.#pow = target;
ret.#miner = miner;
return ret;
}
#eb(k: EventKind) {

View File

@ -20,15 +20,7 @@ export function minePow(e: NostrPowEvent, target: number) {
e.tags.push(["nonce", ctr.toString(), target.toString()]);
}
do {
//roll ctr and compute id
const now = Math.floor(new Date().getTime() / 1000);
// reset ctr if timestamp changed, this is not really needed but makes the ctr value smaller
if (now !== e.created_at) {
ctr = 0;
e.created_at = now;
}
e.tags[nonceTagIdx][1] = (++ctr).toString();
e.id = createId(e);
} while (countLeadingZeros(e.id) < target);