Updates
This commit is contained in:
@@ -1,37 +1,31 @@
|
||||
# hyper-p2p-crdt-version-vector
|
||||
|
||||
Per-peer logical clocks for causality and conflict detection.
|
||||
**Version vector** clock for causal comparison and merge over gossip.
|
||||
|
||||
**Protocol:** `crdt-version-vector/v1`
|
||||
**Category:** State CRDTs · **Protocol:** `crdt-version-vector/v1`
|
||||
|
||||
## When to use
|
||||
|
||||
- Detecting concurrent edits before merging application state.
|
||||
- Tracking causality across replicated peers.
|
||||
Detect concurrent vs ordered events; merge peer clocks from snapshots or wire.
|
||||
|
||||
## When not to use
|
||||
|
||||
- Storing application payload (use LWW register or OR-map).
|
||||
- Global numeric counters (use PN-counter).
|
||||
When you only need LWW timestamps on keys (use LWW register). Full BFT ordering (use `hyper-p2p-causal-consensus`).
|
||||
|
||||
## Quick start
|
||||
|
||||
```js
|
||||
const { HyperP2PCrdtVersionVector } = require('hyper-p2p-crdt-version-vector')
|
||||
const vv = new HyperP2PCrdtVersionVector({ topic: 'vv-demo' })
|
||||
const { HyperP2PCrdtVersionVector, compareVectors } = require('hyper-p2p-crdt-version-vector')
|
||||
const vv = new HyperP2PCrdtVersionVector({ topic: process.argv[2] })
|
||||
await vv.ready()
|
||||
vv.increment('peer-a')
|
||||
const order = vv.compare(vv.toJSON(), { 'peer-b': 2 })
|
||||
await vv.close()
|
||||
console.log(compareVectors(vv.toJSON(), { 'peer-b': 1 }))
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
- [docs/api.md](docs/api.md)
|
||||
- [docs/architecture.md](docs/architecture.md)
|
||||
[docs/api.md](docs/api.md) · [docs/architecture.md](docs/architecture.md)
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
npm install && npm test
|
||||
```
|
||||
`npm install && npm test` · `bare examples/basic.js [topic]`
|
||||
|
||||
@@ -1,21 +1,93 @@
|
||||
# API: hyper-p2p-crdt-version-vector
|
||||
|
||||
**Protocol:** `crdt-version-vector/v1` · **Export:** `HyperP2PCrdtVersionVector`, `compareVectors`
|
||||
**Protocol:** `crdt-version-vector/v1`
|
||||
|
||||
**Export:** `{ HyperP2PCrdtVersionVector, PROTOCOL, compareVectors }`
|
||||
|
||||
## Overview
|
||||
|
||||
`HyperP2PCrdtVersionVector` tracks per-peer logical clocks. `increment(peer)` bumps one slot and gossips. `merge(other)` max-merges remote vector. `compare(a, b)` (also exported as `compareVectors`) returns causal relation: `equal`, `before`, `after`, or `concurrent`.
|
||||
|
||||
## Constructor
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `topic` | `string` \| `Buffer` \| `null` | `null` | Hyperswarm topic |
|
||||
| `keyPair` | `KeyPair` | `hypercore-crypto.keyPair()` | Swarm identity |
|
||||
|
||||
## Methods
|
||||
|
||||
### `increment(peer)`
|
||||
|
||||
Increments this peer's counter and gossips.
|
||||
- **Returns:** `number` — new counter for `peer`
|
||||
- **Throws:** `ValidationError: peer is required`
|
||||
- **Gossip:** `crdt-version-vector-sync`
|
||||
|
||||
### `merge(other)`
|
||||
|
||||
Pointwise max merge: `other` is `{ peerId: count }`.
|
||||
- **Parameters:** `other` — plain object `peer → number`
|
||||
- **Returns:** `number` — slots updated
|
||||
- **Throws:** —
|
||||
|
||||
### `compare(a, b)`
|
||||
|
||||
Returns `'equal' | 'before' | 'after' | 'concurrent'`.
|
||||
Delegates to `compareVectors(a, b)`.
|
||||
|
||||
### `toJSON()` / `getStats()` / `ready()` / `close()`
|
||||
- **Returns:** `'equal' | 'before' | 'after' | 'concurrent'`
|
||||
|
||||
Standard lifecycle; gossip message `crdt-version-vector-sync` with `{ peer, value }`.
|
||||
### `toJSON()`
|
||||
|
||||
- **Returns:** `object` — serializable clock map
|
||||
|
||||
### `async ready()` / `async close()`
|
||||
|
||||
Standard gossip module lifecycle.
|
||||
|
||||
### `getStats()`
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `ops` | `number` | `increment` count |
|
||||
| `gossipIn` / `gossipOut` | `number` | Wire counters |
|
||||
| `peers` | `number` | Distinct peer keys in clock |
|
||||
| `protocol` | `string` | `crdt-version-vector/v1` |
|
||||
|
||||
## compareVectors(a, b)
|
||||
|
||||
Standalone export for tests and `hyper-p2p-causal-consensus` integration.
|
||||
|
||||
| Result | Meaning |
|
||||
|--------|---------|
|
||||
| `equal` | All slots equal |
|
||||
| `after` | `a` strictly dominates `b` |
|
||||
| `before` | `b` strictly dominates `a` |
|
||||
| `concurrent` | Neither dominates |
|
||||
|
||||
## Events
|
||||
|
||||
None emitted.
|
||||
|
||||
## getStats()
|
||||
|
||||
Shallow copy with `peers` count.
|
||||
|
||||
## Wire
|
||||
|
||||
| type | fields | direction | behavior |
|
||||
|------|--------|-----------|----------|
|
||||
| `crdt-version-vector-sync` | `peer`, `value` | bidirectional | `merge({ [peer]: value })` |
|
||||
|
||||
## Errors
|
||||
|
||||
| Message | Source |
|
||||
|---------|--------|
|
||||
| `peer is required` | `increment` |
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
cd modules/state-crdts/hyper-p2p-crdt-version-vector
|
||||
npm install && npm test
|
||||
```
|
||||
|
||||
Unit-test `compareVectors` without network; integration uses shared `topic`.
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
# Architecture: hyper-p2p-crdt-version-vector
|
||||
|
||||
## Model
|
||||
**Protocol:** `crdt-version-vector/v1`
|
||||
|
||||
Map of peer → monotonic integer. `increment(peer)` only advances the local peer entry on this replica; remote peers advance via gossip merge (max).
|
||||
```mermaid
|
||||
flowchart LR
|
||||
App --> VV[HyperP2PCrdtVersionVector]
|
||||
VV --> Clock["_clock Map"]
|
||||
VV --> Cmp[compareVectors]
|
||||
```
|
||||
|
||||
## Compare
|
||||
## Wire messages
|
||||
|
||||
`compareVectors` implements standard dominates relation: `after` if all components ≥ and at least one >; `before` if dominated; `concurrent` if incomparable; `equal` if identical.
|
||||
| type | fields | direction | behavior |
|
||||
|------|--------|-----------|----------|
|
||||
| `crdt-version-vector-sync` | `peer`, `value` | bidirectional | Per-peer max merge |
|
||||
|
||||
## Gossip
|
||||
## State model
|
||||
|
||||
`initModuleSwarm` when `topic` set; inbound sync applies max per peer without re-broadcast.
|
||||
`Map<peerId, number>` — only increases per peer via merge or local increment.
|
||||
|
||||
## Composition
|
||||
|
||||
Used by `hyper-p2p-causal-consensus` (`integrateVectorClock`) and collab stacks for conflict UI.
|
||||
|
||||
@@ -2,10 +2,14 @@ require('bare-process/global')
|
||||
const { HyperP2PCrdtVersionVector, compareVectors } = require('../index.js')
|
||||
|
||||
async function main () {
|
||||
const vv = new HyperP2PCrdtVersionVector()
|
||||
vv.increment('local')
|
||||
vv.merge({ remote: 3 })
|
||||
console.log(vv.toJSON(), compareVectors(vv.toJSON(), { local: 1 }), vv.getStats())
|
||||
const vv = new HyperP2PCrdtVersionVector({ topic: process.argv[2] || null })
|
||||
await vv.ready()
|
||||
vv.increment('peer-a')
|
||||
vv.increment('peer-a')
|
||||
vv.merge({ 'peer-b': 3 })
|
||||
console.log('clock:', vv.toJSON())
|
||||
console.log('compare:', compareVectors(vv.toJSON(), { 'peer-b': 3 }))
|
||||
console.log('stats:', vv.getStats())
|
||||
await vv.close()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user