Hello!
I've been drafting this PR to the webxdc docs for a while, which introduces different concepts for managing shared state in p2p systems and particularly webxdc. The main topic is CRDTs, which guarantee that all clients can compute the same final state once they receive the same set of updates, even if they're received them in different orders.
@hpk and I discussed referencing this app as a minimal example of how to accomplish this without needing to pull in a big library like Yjs. After taking a deeper look at the code, I don't think it guarantees convergence on the same state, though it's very close to being able to do so.
The state of any given pixel is set on every invocation of the update listener, but these aren't guaranteed to arrive in the same order for every recipient, which would cause states to diverge. Differing orders are particularly likely if one or more of two active users queue changes while offline.
I think that this could be mostly avoided by:
-
including an app-specific sequence number in each update, to be used as a Lamport Timestamps (always equal to one greater than the largest known timestamp)
-
adding another array to track the sequence number responsible for setting a particular pixel to its current value
-
checking whether the timestamp for a given pixel is more recent than that of its current pixel before setting a value, and leaving it as-is if the update is older
...and because it's still possible for two users to set the same pixel to a different value with two updates that have equal timestamps
- provide an additional deterministic method to break ties - Yjs uses randomly generated client ids, taking (I think) the lower integer
At first I thought that this was the intent of the current code when I saw its references to update.serial and update.max_serial when applying updates, but if I understand correctly this is only so that it doesn't do a complete redraw of the UI for every internal state change. In any case, @hpk indicated that those two values are set by the local webxdc provider to track the order in which they were received, which makes them unsuitable for my proposed usage.
Anyway, this is a cool app! Assuming I'm not overlooking something and my assessment is correct, I'll be happy to try submitting a PR implementing what I've proposed, or we can chat about different strategies for resolution.
Hello!
I've been drafting [this PR to the webxdc docs](https://github.com/webxdc/webxdc_docs/pull/88) for a while, which introduces different concepts for managing shared state in p2p systems and particularly webxdc. The main topic is CRDTs, which guarantee that all clients can compute the same final state once they receive the same set of updates, even if they're received them in different orders.
@hpk and I discussed referencing this app as a minimal example of how to accomplish this without needing to pull in a big library like Yjs. After taking a deeper look at the code, I don't think it guarantees convergence on the same state, though it's very close to being able to do so.
The state of any given pixel is set [on every invocation of the update listener](https://codeberg.org/webxdc/pixel/src/commit/6c113ff8a6800a349b60bf242377ea6daf763396/script.js#L58), but these aren't guaranteed to arrive in the same order for every recipient, which would cause states to diverge. Differing orders are particularly likely if one or more of two active users queue changes while offline.
I think that this could be mostly avoided by:
1. including an app-specific sequence number in each update, to be used as a [Lamport Timestamps](https://en.wikipedia.org/wiki/Lamport_timestamp) (always equal to one greater than the largest known timestamp)
2. adding another array to track the sequence number responsible for setting a particular pixel to its current value
3. checking whether the timestamp for a given pixel is more recent than that of its current pixel before setting a value, and leaving it as-is if the update is older
...and because it's still possible for two users to set the same pixel to a different value with two updates that have equal timestamps
4. provide an additional deterministic method to break ties - Yjs uses randomly generated client ids, taking (I think) the lower integer
At first I thought that this was the intent of the current code when I saw its references to `update.serial` and `update.max_serial` [when applying updates](https://codeberg.org/webxdc/pixel/src/commit/6c113ff8a6800a349b60bf242377ea6daf763396/script.js#L59-L62), but if I understand correctly this is only so that it doesn't do a complete redraw of the UI for every internal state change. In any case, @hpk indicated that those two values are set by the local webxdc provider to track the order in which they were received, which makes them unsuitable for my proposed usage.
Anyway, this is a cool app! Assuming I'm not overlooking something and my assessment is correct, I'll be happy to try submitting a PR implementing what I've proposed, or we can chat about different strategies for resolution.