Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add verifyPow #315

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

add verifyPow #315

wants to merge 2 commits into from

Conversation

smolgrrr
Copy link

@smolgrrr smolgrrr commented Nov 7, 2023

think this may be worth adding.

for my app get-tao.app, we use PoW filtering and also PoW sorting.
technically the proof side depends on what the user was targeting in the first place.

it's a minor issue at the moment, but ive noticed some notes get onto my high PoW feed while actually targeting a lower difficulty, which indicates the work they've actually put in.
you can see the basic idea with the bottom test.

@smolgrrr
Copy link
Author

smolgrrr commented Nov 7, 2023

i did not change getPow as it's used in minePow, and also don't want this to break any current nip13 implementations.

@alexgleason
Copy link
Collaborator

I don't understand this. This is the function you want:

function verifyPow(event: Event, difficulty: number): boolean {
  return getPow(event.id) >= difficulty;
}

@smolgrrr
Copy link
Author

smolgrrr commented Nov 7, 2023

does this make sense.
it's not a huge thing, but for a signed event, to truly verify PoW it should be checked against the target difficulty specified in the message.

/** Verify POW difficulty for a NOSTR event. */
function verifiedPow(event: Event): number {
  let count = getPow(event.id)

  // Extract the target difficulty level from the tags
  const nonceTag = event.tags.find(tag => tag[0] === 'nonce');
  if (!nonceTag || nonceTag.length < 3) {
    return 0 // Without specifying target difficulty, there is no PROOF of work
  }
  const targetDifficulty = parseInt(nonceTag[2], 10);

  // The proof-of-work is the minimum of actual hash result and target
  return Math.min(count, targetDifficulty)
}

good explanation from nip13.md

The third entry to the nonce tag SHOULD contain the target difficulty. This allows clients to protect against situations where bulk spammers targeting a lower difficulty get lucky and match a higher difficulty. For example, if you require 40 bits to reply to your thread and see a committed target of 30, you can safely reject it even if the note has 40 bits difficulty. Without a committed target difficulty you could not reject it. Committing to a target difficulty is something all honest miners should be ok with, and clients MAY reject a note matching a target difficulty if it is missing a difficulty commitment.

@alexgleason
Copy link
Collaborator

Maybe add this function:

/** Get the target difficulty from the nonce tag, or 0 if no tag exists. */
function getTargetDifficulty(event: Event): number

This will simplify verifyPow. Still, I think its signature should look like this:

function verifyPow(event: Event, difficulty: number): boolean

I can't imagine any case where you don't want to set a lower bound for the difficulty. Why verify POW at all if there's no lower bound?

@smolgrrr
Copy link
Author

smolgrrr commented Nov 7, 2023

hmm not sure, i've chosen this implementation because i currently use it in a similar way to getPow for sorting too, and assume future PoW clients would use it for it's 'number' result.
e.g.

const eventsSortedByPow = [...events].sort((a, b) => verifyPow(b) - verifyPow(a));

i don't mind tho. we could leave this PR open until there are a couple more PoW implementations on nostr and see how ppl deal with it.
i personally think this makes it simpler for clients.

function verifyPow(event: Event): number {
  const hash = getEventHash(event)
  const count = getPow(hash)

  // Extract the target difficulty level from the tags
  const nonceTag = event.tags.find(tag => tag[0] === 'nonce');
  if (!nonceTag || nonceTag.length < 3) {
    return 0 // Without specifying target difficulty, there is no PROOF of work
  }
  const targetDifficulty = parseInt(nonceTag[2], 10);

  // The proof-of-work is the minimum of actual hash result and target
  return Math.min(count, targetDifficulty)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants