From 6db8b9427565e5bbc80a4180ddb5729b6e407750 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 10 Sep 2023 13:40:57 -0500 Subject: [PATCH] nip13: add minePow function --- nip13.test.ts | 16 +++++++++++++++- nip13.ts | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/nip13.test.ts b/nip13.test.ts index e10e2ff..3a65278 100644 --- a/nip13.test.ts +++ b/nip13.test.ts @@ -1,7 +1,21 @@ -import { getPow } from './nip13.ts' +import { getPow, minePow } from './nip13.ts' test('identifies proof-of-work difficulty', async () => { const id = '000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358' const difficulty = getPow(id) expect(difficulty).toEqual(21) }) + +test('mines POW for an event', async () => { + const difficulty = 10 + + const event = minePow({ + kind: 1, + tags: [], + content: 'Hello, world!', + created_at: 0, + pubkey: '79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6', + }, difficulty) + + expect(getPow(event.id)).toBeGreaterThanOrEqual(difficulty) +}) diff --git a/nip13.ts b/nip13.ts index 3472162..3b2bab9 100644 --- a/nip13.ts +++ b/nip13.ts @@ -1,3 +1,5 @@ +import { type UnsignedEvent, type Event, getEventHash } from './event.ts' + /** Get POW difficulty from a Nostr hex ID. */ export function getPow(hex: string): number { let count = 0 @@ -14,3 +16,37 @@ export function getPow(hex: string): number { return count } + +/** + * Mine an event with the desired POW. This function mutates the event. + * Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread. + * + * Adapted from Snort: https://git.v0l.io/Kieran/snort/src/commit/4df6c19248184218c4c03728d61e94dae5f2d90c/packages/system/src/pow-util.ts#L14-L36 + */ +export function minePow(unsigned: UnsignedEvent, difficulty: number): Omit, 'sig'> { + let count = 0 + + const event = unsigned as Omit, 'sig'> + const tag = ['nonce', count.toString(), difficulty.toString()] + + event.tags.push(tag) + + while (true) { + const now = Math.floor(new Date().getTime() / 1000) + + if (now !== event.created_at) { + count = 0 + event.created_at = now + } + + tag[1] = (++count).toString() + + event.id = getEventHash(event) + + if (getPow(event.id) >= difficulty) { + break + } + } + + return event +}