https://video.nostr.build/fe40f309c4458fc0ee83f70cdaa1403703fee22882de409362cf74422d9934f6.mov

As promised, I solved the List Synchronization Problem (your contact list being swiped out problem) for the whole Nostr community so that you don't have to re-invent the algorithm again.

Here is a demonstration with Relay List, which is a harder version of the problem because we also use relays to synchronize the configuration of themselves.

You can open 2 different devices/clients and modify the same list with different values, and they will converge to the same value instead of overriding each other.

Watch what happened from 26s - 28s!

The secret is using a data structure of CRDT. More on this later.

nostr:nprofile1qqsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgspz3mhxue69uhhyetvv9ujuerpd46hxtnfduq3xamnwvaz7tmjv4kxz7tpvfkx2tn0wfnszymhwden5te0dehhxarj9cmrswpwdaexwnanw2j nostr:nprofile1qqsr9cvzwc652r4m83d86ykplrnm9dg5gwdvzzn8ameanlvut35wy3gpp4mhxue69uhkummn9ekx7mqpzpmhxue69uhkummnw3ezuamfdejsz9rhwden5te0wfjkccte9ejxzmt4wvhxjmc3nfy6g nostr:nprofile1qqsyvrp9u6p0mfur9dfdru3d853tx9mdjuhkphxuxgfwmryja7zsvhqppamhxue69uhkummnw3ezumt0d5q36amnwvaz7tmwdaehgu3dwp6kytnhv4kxcmmjv3jhytnwv46qz9rhwden5te0wfjkccte9ehx7um5wghxyecrzy6tn nostr:nprofile1qqsglv2qkn5dmmuhee9cy8fywfu2rfp4xd3xy0myqg2gfvmjl9yqqrqpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq3yamnwvaz7tm0venxx6rpd9hzuur4vg070dh7 nostr:nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5qyv8wumn8ghj7un9d3shjtnwdaehgunpw35jucm0d5q3vamnwvaz7tmjv4kxz7fwdehhxarj9e3xzmnyv0c7x9 nostr:nprofile1qqsfnz2sqsflkatdssmeztxr90s8xrd7r07xkhfwaa6eu9zkcguljpgpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq3kamnwvaz7tmwdaehgu3wwdmkjumn94jku6t8d4sjucmgx9sv8m nostr:nprofile1qqsph3c2q9yt8uckmgelu0yf7glruudvfluesqn7cuftjpwdynm2gygpzpmhxue69uhkummnw3ezuamfdejsz9rhwden5te0wfjkccte9ejxzmt4wvhxjmcpzemhxue69uhhyetvv9ujumn0wd68ytnzv9hxgg6dq49 nostr:nprofile1qqsxu35yyt0mwjjh8pcz4zprhxegz69t4wr9t74vk6zne58wzh0waycpz3mhxue69uhhyetvv9ujumn0wd68ytnzvuqs6amnwvaz7tmwdaejumr0dsq3qamnwvaz7tmwdaehgu3wwa5kuegqrtefg nostr:nprofile1qqs99d9qw67th0wr5xh05de4s9k0wjvnkxudkgptq8yg83vtulad30gpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq32amnwvaz7tm9v3jkutnwdaehgu3wd3skueqprfmhxue69uhhyetvv9ujumn0wd68yurvv438xtnrdaksp8quad nostr:nprofile1qqsqqqqqqzp8l74ff0l29zxrml8yggk8jnamje39k6e3ayzf7u5awqqprpmhxue69uhhwetvvdhk6efwdehhxarj9emkjmn9qyt8wumn8ghj7un9d3shjtnswf5k6ctv9ehx2aqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduy9aajz nostr:nprofile1qqsx8lnrrrw9skpulctgzruxm5y7rzlaw64tcf9qpqww9pt0xvzsfmgprpmhxue69uhhyetvv9ujuumwdae8gtnnda3kjctvqyxhwumn8ghj7mn0wvhxcmmvqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hschfr5x nostr:nprofile1qqs8lft0t45k92c78n2zfe6ccvqzhpn977cd3h8wnl579zxhw5dvr9qprpmhxue69uhhyetvv9ujuumwdae8gtnnda3kjctvqyxhwumn8ghj7mn0wvhxcmmvqyg8wumn8ghj7mn0wd68ytnhd9hx2tvlfps nostr:nprofile1qqsyt3qly8su7u2l5mvu5g9cuqp22axm0w6fa9hw3xp5cek6c4zxk7sprpmhxue69uhhyetvv9ujuumwdae8gtnnda3kjctvqy28wumn8ghj7un9d3shjtnwdaehgu3wvfnszxnhwden5te0dehhxarj9ehhyctwvajhq6tvdshxgetkrz9mhs nostr:nprofile1qqs8hhhhhc3dmrje73squpz255ape7t448w86f7ltqemca7m0p99spgpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq3qamnwvaz7tmwdaehgu3wwa5kuegppamhxue69uhkummnw3ezumt0d5hkly8m nostr:nprofile1qqspqxesa6yvy7snme5t7lyvqcmgaglraqmkg9v4cxr82emarzjx53gpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqs6amnwvaz7tmev9382tndv5qjqamnwvaz7tmjv4kxz7fddfczumn0wd68ytnhd9ex2erwv46zu6nsazpqkk & I forgot the nostr name of strfry author everytime

I'm just tagging more nostr developers I have on top of my head. Feel free to tag & share to other developers & users.

Feedbacks welcome. If the effect in the video is what you consider a solution for the list synchronization problem and upvote this note, I will draft a NIP.

Reply to this note

Please Login to reply.

Discussion

Yes, I'm interested in this, what CRDT did you use? Definitely draft a nip, more robust list building is applicable in many places.

At first I wrote my own, ignorant, didn’t work.

Now it’s Automerge. It has Rust implementation and wasm for JS and the API is simple. Technically the rust implementation can be used everywhere.

Yjs and Yrs should also work but it doesn’t have a good Deno support so I didn’t use.

But one thing I noticed was that parameterized replaceable events were much slower to query comparing to normal events. Maybe strfry isn’t optimized for it yet. Need to test with more relay implementations.

Clever!

This looks cool, but I have a few questions.

In the example you showed each client is creating a different relay list, then when it discovers a relay list created by the other client it merges it.

1. How dose this handle removing different relays in both clients. wouldn't the client just see the relay list from the other client and add the recently removed relay back into the list?

2. Due to how events are spread between relays, A lot of the more obscure relays have really old versions of my relay list. If the app happened to connect to a relay that had a 2+ day old version of my relay list would it attempt to merge it with the newest relay list, even though there are relays that I explicitly wanted to remove?

I like the idea of detecting and merging the relay list. but if it defaults to always merging whatever lists it finds. then I think this could make it difficult to remove relays.

Good questions! Here is a video about removals.

I have 2 browsers open, computer offline.

The left removes nos.lol and the right adds nostr.wine.

Then computer goes online,

the left gets nostr.wine added and the right gets nos.lol removed.

They both converge to the same result list/set no matter how much remove/add you do.

Operations can happen out of order, very old, offline, doesn't matter.

Does this address your concern?

https://video.nostr.build/94209ea5ea637e3c3bd28e1d8063b7b095f2faefa71ca6d03399906786ab05d9.mov

CRDT - Conflict-free Replicated Data Type

CRDTs ensure that, no matter what data modifications are made on different replicas, the data can always be merged into a consistent state.

https://crdt.tech/