diff --git a/src/handlers/event-message-handler.ts b/src/handlers/event-message-handler.ts index 14d5427..b51a14e 100644 --- a/src/handlers/event-message-handler.ts +++ b/src/handlers/event-message-handler.ts @@ -1,6 +1,6 @@ import { EventDelegatorMetadataKey, EventTags } from '../constants/base' +import { getEventProofOfWork, getPubkeyProofOfWork, isDelegatedEvent, isDelegatedEventValid, isEventIdValid, isEventSignatureValid } from '../utils/event' import { IEventStrategy, IMessageHandler } from '../@types/message-handlers' -import { isDelegatedEvent, isDelegatedEventValid, isEventIdValid, isEventSignatureValid } from '../utils/event' import { Event } from '../@types/event' import { Factory } from '../@types/base' import { IncomingEventMessage } from '../@types/messages' @@ -67,5 +67,17 @@ export class EventMessageHandler implements IMessageHandler { return `created_at is more than ${limits.createdAt.maxNegativeDelta} seconds in the past` } } + + if (limits.eventId.minLeadingZeroBits > 0) { + if (getEventProofOfWork(event) < limits.eventId.minLeadingZeroBits) { + return `insufficient proof of work: eventId has less than ${limits.eventId.minLeadingZeroBits} leading zero bits` + } + } + + if (limits.pubkey.minLeadingZeroBits > 0) { + if (getPubkeyProofOfWork(event.pubkey) < limits.pubkey.minLeadingZeroBits) { + return `insufficient proof of work: pubkey has less than ${limits.pubkey.minLeadingZeroBits} leading zero bits` + } + } } } diff --git a/src/utils/event.ts b/src/utils/event.ts index f4092ea..b16fa8e 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -4,7 +4,9 @@ import { applySpec, converge, curry, mergeLeft, nth, omit, pipe, prop, reduceBy import { CanonicalEvent, Event } from '../@types/event' import { EventKinds, EventTags } from '../constants/base' import { fromBuffer } from './transform' +import { getLeadingZeroBits } from './proof-of-work' import { isGenericTagQuery } from './filter' +import { Pubkey } from '../@types/base' import { RuneLike } from './runes/rune-like' import { SubscriptionFilter } from '../@types/subscription' @@ -135,7 +137,7 @@ export const isDelegatedEventValid = async (event: Event): Promise => { if (!result) { return false - } + } const serializedDelegationTag = `nostr:${delegation[0]}:${event.pubkey}:${delegation[2]}` @@ -175,3 +177,11 @@ export const isEphemeralEvent = (event: Event): boolean => { export const isDeleteEvent = (event: Event): boolean => { return event.kind === EventKinds.DELETE } + +export const getEventProofOfWork = (event: Event): number => { + return getLeadingZeroBits(Buffer.from(event.id, 'hex')) +} + +export const getPubkeyProofOfWork = (pubkey: Pubkey): number => { + return getLeadingZeroBits(Buffer.from(pubkey, 'hex')) +} diff --git a/src/utils/proof-of-work.ts b/src/utils/proof-of-work.ts new file mode 100644 index 0000000..efa956c --- /dev/null +++ b/src/utils/proof-of-work.ts @@ -0,0 +1,26 @@ +export function getLeadingZeroBits(hash: Buffer) { + let total: number, i: number, bits: number + + for (i = 0, total = 0; i < hash.length; i++) { + bits = msb(hash[i]) + total += bits + if (bits != 8) { + break + } + } + return total +} + +function msb(b: number) { + let n = 0 + + if (b == 0) { + return 8 + } + + while (b >>= 1) { + n++ + } + + return 7 - n +} diff --git a/src/utils/settings.ts b/src/utils/settings.ts index 09660b8..9b1ccd8 100644 --- a/src/utils/settings.ts +++ b/src/utils/settings.ts @@ -38,7 +38,7 @@ const getDefaultSettings = (): ISettings => ({ }, createdAt: { maxPositiveDelta: 900, // +15 min - maxNegativeDelta: 31536000, // -1 year + maxNegativeDelta: 0, // disabled }, }, client: {