Skip to content

Instantly share code, notes, and snippets.

@motorina0
Last active June 13, 2023 15:16
Show Gist options
  • Save motorina0/874912282d2419be4eaf89de8d0c4464 to your computer and use it in GitHub Desktop.
Save motorina0/874912282d2419be4eaf89de8d0c4464 to your computer and use it in GitHub Desktop.

Note A NIP PR has been open here, the conversation should move to the PR

Problem

Ratings give the reputation for a person, service or product. They are important for creating an open and free-market. It helps participants make decisions based on what their peers previously experienced with that person, services or product.

Having a rating system in an open and decentralized system (like nostr) is hard because anyone can join and give ratings. Thus bots will be created to overtake the honest human's votes.

Some solutions have been proposed for this problem, but none of them is satisfactory (see first comment).

Suggested Solution

In order to avoid spam, each rating must have associated with it the proof that a tiny fee has been paid. The fee should not be paid to a centralized service that can cheat (see first comment), but to an impartial, decentralized system (like the bitcoin blockchain).

Rating Mass

A user can register its public key in a Merkle tree and the root of the tree is then persisted (by a specialized service) on the bitcoin blockchain using the OP_RETURN operator (thus paying a fee). Similarly with what open-timestamps does.

If the public key is registered as the root of the tree then the rating mass is 1, if it is registered on the second level then the rating mass is 1/2 (there can be two leaves). The lower one goes in the tree, the more leaves it can register, but also the less each leaf is worth (rating mass is 1/2n where n is the depth - starting at 0).

The properties of the tree are:

  • Each leaf is of the form: [<tree-level>, <leaf-index>, <public-key>].
  • Leaves can exist at any level. The closer to the tree root a leaf is, the more valuable it is.

rating-points-tree drawio(4)

Highlighted in the image is the path to leaf [4, 0, a728...] which is composed of 4 elements: [hash([4,1,a728...]), H2, H7, H9]. This path has a rating mass of 1/4.

For the above example (image), the public key a728... (yellow rectangles) has purchased 9 rating options with a total mass of 0.8125 (2 * 1/22 + 2 * 1/24 + 4 * 1/25), whereas public key 1acf... (purple rectangles) has purchased 3 rating options with a mass of 0.1875 (3 * 1/24). The total mass of the tree will always be 1 (eg: 0.8125 + 0.1875), because everybody knows that 1+2+4+⋯+2𝑛 = 2𝑛+1 - 1.

Rating Mass is not the Rating Value

The rating value can be an integer between 1 and 5, or it can be a float between 0 and 1 (see this NIP-32 PR), or any other rating system.

The rating mass represents the importance or intensity that a user gives to a particular rating. It also guarantees that the rating is not spam.

For example I might dislike a film and give it a rating value of 2 stars and a rating mass of 0.03125 (consume a leaf on level 5 of the tree: 1/25). Or I might dislike that the Uber driver just dropped me off in a bad neighborhood and give it a rating value of 2 stars, but a rating mass of 0.5 (consume a leaf on level 1 of the tree: 1/21, more intense).

Using Rating Mass in Nostr

Ratings in nostr can be achieved by publishing a particular event (see this NIP-32 PR to get an idea of how the event could look like) and attaching a rating mass to the event.

This rating event should be a Parameterized Replaceable Events (NIP-33) and have these additional tags representing the rating mass:

{
  "kind": 30030,
  "pubkey": <public key of the event creator>,
  "tags": [
    ["tx-id", <id of the transaction where the `OP_RETURN` was included>],
    ["output-index", <index of the `OP_RETURN` output>],
    ["leaf", <tree-level>, <leaf-index>, <public-key of the event creator>],
    ["leaf-path", <hash1>, <hash2>, ...],
    ["d", <hash(tx-id, output-index, <tree-level>, <leaf-index>, <public-key>, <hash1>, <hash2>, ...)>],
    ...
  ],
  "content": "...",
  ...
}

The d tag is the most important one because it aggregates all the other values and because it is the one used to replace the NIP-33 event. This means that the same leaf cannot be used in two different rating events. Trying to reuse the leaf will simply replace the previous rating event. On the other hand, if I have "consumed" one of my ratings for liking a song that I later discover it was plagiarised then I can take that rating back and reuse it one something else.

Note The public key in the leaf must be the same as the public key of the event creator.

Note Rating events without a rating mass or which have a very long path (are almost free) should not be taken into consideration

Next Steps

  • detailed doc for the tree structures

  • create a services that allows users to buy rating mass

    • the user selects the levels it wants to register it public key at
    • the services computes the cost
    • the user pays the invoice and receives the full tree
  • create a service that computes ratings based on the rating mass assigned to each rating event

    • this can be part of the relay, or a standalone service
  • integrate with social media clients, market clients, etc

@arcbtc
Copy link

arcbtc commented Jun 13, 2023

Beyond pow or oracles having a cost is clearly the best solution. I like weighted reviews based on cost, its up to the platform whether they want to use that metric, but it adds another dimension. As with other systems that are easy to trick (such as aliexpress), it will also be up to the user to click through the ratings and see if they are legit. I imagine later, some extra weight could be added if the npub has a verified tick, by some kyc relay/identity verifying relay.

@ralyodio
Copy link

neat-o

@Rsync25
Copy link

Rsync25 commented Jun 13, 2023

Awesome!

@motorina0
Copy link
Author

Note
A NIP PR has been open here, the conversation should move to the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment