Nobody else seems to care but I think nostr finally needs a Hash Chain event kind or tag that is enforced server-side: - To add a new event to the chain, you MUST reference a previous event. If the referenced event does not exist, you get an error. - Only one event can reference another event. If an event has already been referenced before, you get an error. IMO (almost) solves the biggest issue with nostr which is the fact that you never know if the data you have is complete and it allows atomic updates of data. Suggestions for improvements of this idea welcome.

Replies (43)

This was discussed a lot several years ago and I don't recall the reasons for the pushback at the time. I do agree that without this change, we do get lost replies and lost data. It's hard to reconstruct the whole conversation. That said, Outbox/Inbox does help here. @fiatjaf do you remember why this was not favorable?
it can work for nip60 since the relay set is (supposed to) be well set; but for the overall nostr that gets you into fork hell NIP-29 does this (kinda) with the `prev` tag because the relay you are publishing is well known, so you have a natural central repository of state -- it doesn't mandate rejecting events at all, but it gives you some type of contextual ordering of events in time.
Secure Scuttlebutt. Older than Nostr, and truly peer-to-peer. No holes in the convo there... if anything is missing, the client cannot decrypt and verify subsequent replies. I firmly believe this is worse, and the Achilles Hell of an otherwise brilliant endeavour.
forking across relays is what you mean I suppose? in that case, I can resolve the fork with precision. I just need the relay to tell me I can or can't write this data. There is no other way.
Yes this is what I love about it but let's just make this a special event kind only for applications that need it
a database works because its a single source of truth. what happens when you successfully publish to two relays from two clients without awareness of each other (which with any network flakiness will constantly happen)
but how would the relay know if it can't know the final state? it can only allow/reject locally, unknowingly allowing a fork
but that's what I mean, if you say "I publish these event kind in relay A" then you can scope the chain to that relay and have a locally enforced chain that works (this is why I wanted to add the `relay` tag to the NIP-60 wallet event) because it makes the state of a known number of relays authoritative.
Nusa's avatar
Nusa 3 days ago
This is a Git-shaped problem. You mught not need a new kind. You want a relay-distributed repository with deterministic branch management: content-addressed objects, explicit parentage, fast-forward rules, detectable forks, and a current tip that relays can announce.
The second requirement sounds like a DoS problem for clients, desperately having to look for an unclaimed event. And it'll be different per relay. The first requirement also has the problem that each relay may have a different view, but at least you could first query relays to find out. Enforcing this client side would be easier. There's also a bootstrap issue.
The proposal: Like replaceable events but you have to be explicit which event you are replacing? I would or maybe publicly did call that versioned event. You get a chain and relays should retain older versions up the chain for a while, so when a buggy client nukes your contact list, the nuking event would hold a reference to the probably still available event with your old state. If relays diverge, you have to walk back and delete bad events on those diverging relays.
It must be relay side and yes a special relay for a special event kind would be great
no, that's way too much. Just give me the linked list and I'll figure out the rest
that's the only really problem but the bigger problem is that EVEN IF I HAVE ONLY ONE RELAY I CANT GET ANY DATA CONSISTENCY GUARANTEES AND IT DRIVES ME NUTS
all the relay needs to do is what I said above, it doesn't need to do anything else. Maybe I'm not sure what you meant
Solved this years ago but no one cared. You create a Merkle tree of your post hashes, as a catalog for your account. The posts can still be individual, but the tree serves as a guide for if anything is missing. You don’t need a chain. Problem is, two devices trying to update the tree (or your chain idea) at once may have a conflict — or during a partition among relays etc — so UI would be needed for fixing the tree. Gets a bit tricky due to many devices due to the CAP theorem.
How would this work with unreliable relays? If I can't find the event that you reference, is it because you've fabricated a reference, or because I simply don't have access to your earlier event?
RamenCoffee's avatar
RamenCoffee 3 days ago
Nostr will never give you thay guarantee by design. If that was the case, relays could start threads with a secret post and no one could respond without writing access that relay. Effectively censorship.
RamenCoffee's avatar
RamenCoffee 3 days ago
Being non-resistant to the state does come with concienience in design
CRDTs could be a viable alternative for this (for those complaining about holes breaking SSB and stuff).
Puts pkarr homeservers in a different light, doesn't it?
This is interesting for specific use cases. Have you read the nostr state machines I wrote some time ago? It uses dag as you mentioned Also have you checked cordn by @Besao ? It solves that problem but for mls over nostr which requires strong ordering. In any case you don't need an special relay for this, a cvm acting as ordering oracle gives you that without deployment complexity
Are there any other protocols doing it the merkle tree way? Bluesky, pubky, matrix, ...? Or what do they do all they do?
Nuh's avatar
Nuh 3 days ago
Matrix is a graph not tree. Bluesky has a tree, yet no one cares to check and just trust the relay, after they found the tree proof too heavy and they clients don't care, Pubky doesn't use a tree because it would have required so much work and I knew no one gives a fuck not even in Nostr whether or not events are signed, you can always check the source of truth manually But a merkle tree is more than just a cheap signature over so many files, it also gives data integrity when you migrate, so you know you got all your files. So Pubky should eventually backfill that, but I can't tell them what to do. Peergos uses a Cryptree, but that doesn't just do data integrity, but makes encryption and read/write access control viable... Not to mention that Nostr Damus relay (Strfry) uses a database that is itself a copy on write tree (LMDB) ... Just not merklized. Of course all databases are trees, but LMDB is just flat out simple tree that could easily be merklized. So theoretically, you should assume that any database is a tree, and there are reasons to merklize it, and other reasons to encrypt it
HAHAHHAHAHA I thought bull market was back on for a second if you're querying a single relay it'll give you everything assuming you paginate, etc, etc but again, for what you want I'd make a custom relay that enforces a per-kind consistency rule since I'm guessing whatever you're doing needs complete data consistency assurance (i.e. better to have an event rejected than inconsistent state)
data consistency has a price; the question is not when you don't want it, it's how much you're paying for it everybody also wants 100% uptime -- how much are you willing to pay for it?
Oh in so many cases, consistency is tricky, specially in nostr since there is no consistency requirements unlike in a blockchain. Would all relays need to be consistent? That would make nostr a blockchain. Would just a set of relays enforce consistency, what does that means to other relays that are not in that federation? Would that means loss of portability?
Yes! but I won't really bother fixing it with duck tape (state machines) because it's mathematically impossible to build consistent systems without the relay (db) enforcing a mutex.
This does not (can't) prevent forks across multiple relays because relays would have to coordinate for this. I won't try to fix an unfixable problem. The bigger issue is that we don't even have consistency for ONE relay, let alone multiple. For multiple relays, you can still improve (not fully fix) the situation by ordering the writes deterministically across devices. So if a device has relay set ABC, you would first write on A, then on B, then on C. If every device does this, you can't fork. If one of the relays (A) goes offline for a bit then comes back, and you're already advanced to stage x+1, then you wouldn't be able to write x+1 to A and would have to fill in A with the missing event x. If two devices had two disjunct relay lists, you will fork and there is no way to prevent that without forcing relays to coordinate, which we don't want.