By introducing a small limitation: only allowing entries in the change
graph to be addressable, instead of individual operations; we
drastically simplify the CRDT implementation.
There are four advantages:
1. Op ids are just regular SHA-1s
2. There's no need for relative IDs, ops never refer to other ops within the
same commit
3. There's no need for a nonce, since commits can't collide, and neither can op IDs
4. `OpId` can just be an alias of `EntryId`
The disadvantage of course, is that we have to be mindful of how we
create op transactions, since each transaction creates an addressable
unit. For example, we must not include multiple patch revisions in the
same transaction.
It's fairly easy for a user to (by mistake or intentionally) create two
operations with the same OpId. This patch makes it much less likely,
and ensures that if the OpId is equal, it's because the operations
are identical.
By using `0` as the clock value for an empty state (without operations),
we simplify transaction code. Previously, there was no clock value for
empty states, which meant that we had to sometimes use an `Option`.
We're using petgraph to encode an operation based CRDT (each graph node
is an operation) as a DAG, and one of the important things to ensure
is that the final state is not influenced by the order of concurrent
operations. In this case a concurrent operation would mean two potential
graph traversal orders, as there's no direct edge between the two
concurrent ops. This is essential a "partial order" of operations.
To be able to test this, we'd want some kind of control over how
neighbors are iterated over I guess, when there's more than one possible
sort order. Say we have a graph like this:
┌────────b◄─────┐
▼ │
a d
▲ │
└────────c◄─────┘
There are two possible topological traverse orders: [a, b, c, d] and [a,
c, b, d]. Having a way to go through these different orders would
be super handy.
One option would be to allow random order traversal. This would allow us
to test all orders by running the test enough times to likely test all
permutations.
Since petgraph doesn't support this, we implement our own simple DAG in
`radicle-dag`, which implements random-order topological orders.
For now, we don't make explicit use of these improvements, we simply
replace the underlying graph with our own.
We weren't accounting for batches ops in an entry.
This change should account for it by adding N-1
to the clock value of an entry, where N is the number
of entries.
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This is a minimal port of the collaborative objects code from
radicle-link[0].
A `CollaborativeObject` is made up of a `History` of `Change`s that
are expected to be stored in a `git` backend.
The library exposes a CRU series of functions `create`, `get`, `list`,
and `update`.
This implementation differs, to previous one, in that it does not
assume any kind of identity system -- its only assumption is that
identities have an identifier and can be addressed in the `git`
database. This means that it does not require an `author` to be passed
in and it only uses the `resource` (previously `authorizing_identity`)
to store its content-address in the `Change`.
It also foregoes any caching to simplify the port and not make any
early optimisation assumptions.
[0]: https://github.com/radicle-dev/radicle-link/tree/master/cob
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>