Compare commits

...

2 Commits

Author SHA1 Message Date
fiatjaf
e45a9987e2 pool: prevent edge case with undefined subcloser. 2026-02-12 15:08:13 -03:00
fiatjaf
0c2c2cd4d8 nip13: improve mining by skipping hex. 2026-02-08 01:06:01 -03:00
4 changed files with 30 additions and 14 deletions

View File

@@ -16,8 +16,7 @@ import { Relay } from './relay.ts'
export type SubCloser = { close: (reason?: string) => void } export type SubCloser = { close: (reason?: string) => void }
export type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & { export type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {
// automaticallyAuth takes a relay URL and should return null // automaticallyAuth takes a relay URL and should return null in case that relay shouldn't be authenticated against
// in case that relay shouldn't be authenticated against
// or a function to sign the AUTH event template otherwise (that function may still throw in case of failure) // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)
automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>) automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)
// onRelayConnectionFailure is called with the URL of a relay that failed the initial connection // onRelayConnectionFailure is called with the URL of a relay that failed the initial connection
@@ -269,10 +268,13 @@ export class AbstractSimplePool {
filter: Filter, filter: Filter,
params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>, params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,
): SubCloser { ): SubCloser {
const subcloser = this.subscribe(relays, filter, { let subcloser: SubCloser
subcloser = this.subscribe(relays, filter, {
...params, ...params,
oneose() { oneose() {
subcloser.close('closed automatically on eose') const reason = 'closed automatically on eose'
if (subcloser) subcloser.close(reason)
else params.onclose?.(relays.map(_ => reason))
}, },
}) })
return subcloser return subcloser

View File

@@ -1,6 +1,6 @@
{ {
"name": "@nostr/tools", "name": "@nostr/tools",
"version": "2.23.0", "version": "2.23.1",
"exports": { "exports": {
".": "./index.ts", ".": "./index.ts",
"./core": "./core.ts", "./core": "./core.ts",

View File

@@ -21,6 +21,23 @@ export function getPow(hex: string): number {
return count return count
} }
/** Get POW difficulty directly from a Uint8Array hash. */
function getPowFromBytes(hash: Uint8Array): number {
let count = 0
for (let i = 0; i < hash.length; i++) {
const byte = hash[i]
if (byte === 0) {
count += 8
} else {
count += Math.clz32(byte) - 24
break
}
}
return count
}
/** /**
* Mine an event with the desired POW. This function mutates the event. * 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. * Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread.
@@ -43,18 +60,15 @@ export function minePow(unsigned: UnsignedEvent, difficulty: number): Omit<Event
tag[1] = (++count).toString() tag[1] = (++count).toString()
event.id = fastEventHash(event) const hash = sha256(
utf8Encoder.encode(JSON.stringify([0, event.pubkey, event.created_at, event.kind, event.tags, event.content])),
)
if (getPow(event.id) >= difficulty) { if (getPowFromBytes(hash) >= difficulty) {
event.id = bytesToHex(hash)
break break
} }
} }
return event return event
} }
export function fastEventHash(evt: UnsignedEvent): string {
return bytesToHex(
sha256(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))),
)
}

View File

@@ -1,7 +1,7 @@
{ {
"type": "module", "type": "module",
"name": "nostr-tools", "name": "nostr-tools",
"version": "2.23.0", "version": "2.23.1",
"description": "Tools for making a Nostr client.", "description": "Tools for making a Nostr client.",
"repository": { "repository": {
"type": "git", "type": "git",