An open API service indexing awesome lists of open source software.

https://github.com/mizchi/converge

EG-walker CRDT
https://github.com/mizchi/converge

argorithm crdt moonbit

Last synced: 5 days ago
JSON representation

EG-walker CRDT

Awesome Lists containing this project

README

          

# mizchi/converge

EG-Walker にインスパイアされた MoonBit 製ローカルファースト DB 同期エンジン。

[English](README.md)

## 2層アーキテクチャ

```
┌──────────────────────────────────────────────────┐
│ Application │
├───────────────────────┬──────────────────────────┤
│ Durable Layer │ Ephemeral Layer │
│ (CrdtDoc) │ (EphemeralStore) │
│ │ │
│ - Event Graph │ - LWW Register Map │
│ - Causal ordering │ - Timestamp + PeerId │
│ - RLE compressed │ - No history │
│ - Conflict-free │ - Overwrite semantics │
│ merge (EG-Walker) │ │
│ │ │
│ Use: DB CRUD, │ Use: Cursors, presence, │
│ document edits │ player positions, typing │
│ │ indicators │
├───────────────────────┴──────────────────────────┤
│ Sync Transport │
│ HTTP (push/pull) │ WebSocket (broadcast) │
└──────────────────────────────────────────────────┘
```

**Durable Layer** は因果イベントグラフに全操作を Lamport タイムスタンプ付きで記録する。完全な履歴と決定論的な競合解決が必要な低頻度操作に最適。

**Ephemeral Layer** は名前空間ごとの LWW レジスタを使用。イベントグラフのオーバーヘッドなし。最新値のみが重要な高頻度・短命な状態向け。

## パッケージ構成

```
src/
├── types/ コア型定義 (PeerId, EventId, Value, RowOp, Event, EventRun)
├── clock/ Lamport 論理クロック
├── graph/ フロンティア追跡と LCA 計算付きイベント DAG
├── oplog/ RLE 圧縮付き操作ログ
├── merge/ EG-Walker 競合解決(列単位 LWW)
├── doc/ CrdtDoc — Durable Layer の高レベル API
├── ephemeral/ EphemeralStore — LWW レジスタマップ(Ephemeral Layer)
├── bft/ BFT-CRDT アダプター(ビザンチン障害検出)
├── sync/ 同期プロトコル (PushRequest, PullRequest, PullResponse)
├── topology/ ネットワークトポロジシミュレーション (Star, Gossip, Mesh 等)
├── wasm/ 両レイヤーの WASM/JS エクスポート
└── e2e/ E2E 統合テスト
```

## ビルドターゲット

```bash
moon build --target wasm-gc # WASM-GC 出力
moon build --target js # JavaScript 出力
moon test # 全テスト実行
```

## 使い方

### Durable Layer (CrdtDoc)

永続的で競合のないデータ向け:

```
create_doc(peer_id) -> handle
doc_insert(handle, tbl, row_id, values_json)
doc_update(handle, tbl, row_id, col, value_json)
doc_delete(handle, tbl, row_id)
doc_merge_remote(handle, events_json)
doc_get_pending(handle, known_json)
doc_sync_state(handle)
```

### Ephemeral Layer (EphemeralStore)

一時的で高頻度な状態向け:

```
ephemeral_set(handle, ns, key, value_json, timestamp)
ephemeral_get(handle, ns, key)
ephemeral_get_all(handle, ns)
ephemeral_merge(handle, entries_json)
```

## WebAssembly Component

`component/` ディレクトリに [WebAssembly Component Model](https://component-model.bytecodealliance.org/) パッケージを提供。WIT で全型を定義しており、JSON シリアライズ不要で canonical ABI を直接使用する。

```bash
cd component
just build # .wasm コンポーネントをビルド
just test # ビルド + jco transpile + Node.js テスト
```

jco (JavaScript) での使用例:

```js
import { converge } from './gen/converge-component.js';

const handle = converge.createDoc("peer-A");
converge.docInsert(handle, "users", "row1", [
{ key: "name", val: { tag: "val-str", val: "Alice" } },
{ key: "age", val: { tag: "val-int", val: 30 } },
]);

const h2 = converge.createDoc("peer-B");
const pending = converge.docGetPending(handle, []);
const ops = converge.docMergeRemote(h2, pending);
```

API リファレンスと型定義の詳細は [component/README.md](component/README.md) を参照。

## BFT Layer (Byzantine Fault Tolerance)

P2P 環境でのチート検出のため、Kleppmann の "Making CRDTs Byzantine Fault Tolerant" (PaPoC 2022) に基づく検証レイヤー。既存の Durable Layer を変更せず、アダプターとして上に乗る設計。

```
[Application]
|
[CrdtDoc] <- 変更なし
|
[BFTAdapter] <- deliver() で検証後、CrdtDoc に渡す
|
[Transport] <- 変更なし
```

`BFTAdapter::deliver(signed_event)` は受信した `SignedEvent` に対し以下を順に検証する:

1. **Hash 整合性** — イベント内容を再シリアライズしてハッシュを再計算、不一致なら拒否
2. **署名検証** — `Verifier` trait で author_key に対する署名を検証
3. **Equivocation 検出** — 同一 `(peer, counter)` に異なる digest が来た場合拒否
4. **因果配送** — 依存する digest が未到着の場合バッファリングし、到着次第フラッシュ

暗号プリミティブは `Hasher` / `Signer` / `Verifier` trait で抽象化されており、テスト用の FNV-1a + Mock 実装と、本番用の SHA-256 + Ed25519 実装を差し替え可能。

## 推奨バックエンドアダプター

| プラットフォーム | レイヤー | WASM ターゲット | 同期方式 | Example |
|----------|--------|-------------|------|---------|
| **Cloudflare Workers + Durable Objects** | Durable + Ephemeral | `js` | HTTP push/pull + WebSocket | `examples/cf-do/` |
| **Deno Deploy + Deno KV** | Durable | `wasm-gc` | HTTP push/pull | `examples/deno-deploy/` |

### Cloudflare Workers + Durable Objects(推奨)

本番利用に最適。ドキュメントごとに単一の Durable Object インスタンスが CRDT 状態と永続ストレージ(DO Storage)を同一ロケーションに配置する。HTTP エンドポイントで Durable Layer の push/pull 同期を行い、WebSocket 接続で Ephemeral Layer の状態をリアルタイム配信する。

- Durable Layer: イベントを `event:` キーで DO Storage に永続化、起動時に `blockConcurrencyWhile()` でリプレイ
- Ephemeral Layer: LWW マージによる WebSocket リレー(プレゼンス、カーソル、ゲーム状態)
- CF Workers の制約に対応するため WASM は dynamic import で読み込み

### Deno Deploy + Deno KV

Deno KV を永続化に使う軽量な選択肢。catchUp メカニズムにより、他のアイソレートが書き込んだイベントを検出するマルチアイソレート並行処理に対応。WASM-GC ターゲット + JS String Builtins を使用。

- 大きな EventRun は 50 操作単位に分割(KV の 64KB 値制限対応)
- 最大 10 ミューテーションのアトミックバッチ書き込み

### その他の Example

- `examples/cf-do-game/` — マルチプレイ対応 Vampire Survivors 風ブラウザデモ(Ephemeral Layer + DOゲームループ、WebSocket)
- `examples/cf-signaling/` — Star/Gossip トポロジ切替可能な P2P シグナリングリレー(Ephemeral Layer のみ、WebSocket)

## License

Apache-2.0