@optimystic/db-p2p 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/dist/index.min.js +52 -0
  2. package/dist/index.min.js.map +7 -0
  3. package/dist/src/cluster/client.d.ts +12 -0
  4. package/dist/src/cluster/client.d.ts.map +1 -0
  5. package/dist/src/cluster/client.js +65 -0
  6. package/dist/src/cluster/client.js.map +1 -0
  7. package/dist/src/cluster/cluster-repo.d.ts +79 -0
  8. package/dist/src/cluster/cluster-repo.d.ts.map +1 -0
  9. package/dist/src/cluster/cluster-repo.js +613 -0
  10. package/dist/src/cluster/cluster-repo.js.map +1 -0
  11. package/dist/src/cluster/partition-detector.d.ts +59 -0
  12. package/dist/src/cluster/partition-detector.d.ts.map +1 -0
  13. package/dist/src/cluster/partition-detector.js +129 -0
  14. package/dist/src/cluster/partition-detector.js.map +1 -0
  15. package/dist/src/cluster/service.d.ts +49 -0
  16. package/dist/src/cluster/service.d.ts.map +1 -0
  17. package/dist/src/cluster/service.js +107 -0
  18. package/dist/src/cluster/service.js.map +1 -0
  19. package/dist/src/index.d.ts +29 -0
  20. package/dist/src/index.d.ts.map +1 -0
  21. package/dist/src/index.js +29 -0
  22. package/dist/src/index.js.map +1 -0
  23. package/dist/src/it-utility.d.ts +4 -0
  24. package/dist/src/it-utility.d.ts.map +1 -0
  25. package/dist/src/it-utility.js +32 -0
  26. package/dist/src/it-utility.js.map +1 -0
  27. package/dist/src/libp2p-key-network.d.ts +59 -0
  28. package/dist/src/libp2p-key-network.d.ts.map +1 -0
  29. package/dist/src/libp2p-key-network.js +278 -0
  30. package/dist/src/libp2p-key-network.js.map +1 -0
  31. package/dist/src/libp2p-node.d.ts +28 -0
  32. package/dist/src/libp2p-node.d.ts.map +1 -0
  33. package/dist/src/libp2p-node.js +270 -0
  34. package/dist/src/libp2p-node.js.map +1 -0
  35. package/dist/src/logger.d.ts +3 -0
  36. package/dist/src/logger.d.ts.map +1 -0
  37. package/dist/src/logger.js +6 -0
  38. package/dist/src/logger.js.map +1 -0
  39. package/dist/src/network/get-network-manager.d.ts +4 -0
  40. package/dist/src/network/get-network-manager.d.ts.map +1 -0
  41. package/dist/src/network/get-network-manager.js +17 -0
  42. package/dist/src/network/get-network-manager.js.map +1 -0
  43. package/dist/src/network/network-manager-service.d.ts +82 -0
  44. package/dist/src/network/network-manager-service.d.ts.map +1 -0
  45. package/dist/src/network/network-manager-service.js +283 -0
  46. package/dist/src/network/network-manager-service.js.map +1 -0
  47. package/dist/src/peer-utils.d.ts +2 -0
  48. package/dist/src/peer-utils.d.ts.map +1 -0
  49. package/dist/src/peer-utils.js +28 -0
  50. package/dist/src/peer-utils.js.map +1 -0
  51. package/dist/src/protocol-client.d.ts +12 -0
  52. package/dist/src/protocol-client.d.ts.map +1 -0
  53. package/dist/src/protocol-client.js +34 -0
  54. package/dist/src/protocol-client.js.map +1 -0
  55. package/dist/src/repo/client.d.ts +17 -0
  56. package/dist/src/repo/client.d.ts.map +1 -0
  57. package/dist/src/repo/client.js +82 -0
  58. package/dist/src/repo/client.js.map +1 -0
  59. package/dist/src/repo/cluster-coordinator.d.ts +59 -0
  60. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -0
  61. package/dist/src/repo/cluster-coordinator.js +539 -0
  62. package/dist/src/repo/cluster-coordinator.js.map +1 -0
  63. package/dist/src/repo/coordinator-repo.d.ts +29 -0
  64. package/dist/src/repo/coordinator-repo.d.ts.map +1 -0
  65. package/dist/src/repo/coordinator-repo.js +102 -0
  66. package/dist/src/repo/coordinator-repo.js.map +1 -0
  67. package/dist/src/repo/redirect.d.ts +14 -0
  68. package/dist/src/repo/redirect.d.ts.map +1 -0
  69. package/dist/src/repo/redirect.js +9 -0
  70. package/dist/src/repo/redirect.js.map +1 -0
  71. package/dist/src/repo/service.d.ts +52 -0
  72. package/dist/src/repo/service.d.ts.map +1 -0
  73. package/dist/src/repo/service.js +181 -0
  74. package/dist/src/repo/service.js.map +1 -0
  75. package/dist/src/repo/types.d.ts +7 -0
  76. package/dist/src/repo/types.d.ts.map +1 -0
  77. package/dist/src/repo/types.js +2 -0
  78. package/dist/src/repo/types.js.map +1 -0
  79. package/dist/src/routing/libp2p-known-peers.d.ts +4 -0
  80. package/dist/src/routing/libp2p-known-peers.d.ts.map +1 -0
  81. package/dist/src/routing/libp2p-known-peers.js +19 -0
  82. package/dist/src/routing/libp2p-known-peers.js.map +1 -0
  83. package/dist/src/routing/responsibility.d.ts +14 -0
  84. package/dist/src/routing/responsibility.d.ts.map +1 -0
  85. package/dist/src/routing/responsibility.js +45 -0
  86. package/dist/src/routing/responsibility.js.map +1 -0
  87. package/dist/src/routing/simple-cluster-coordinator.d.ts +23 -0
  88. package/dist/src/routing/simple-cluster-coordinator.d.ts.map +1 -0
  89. package/dist/src/routing/simple-cluster-coordinator.js +59 -0
  90. package/dist/src/routing/simple-cluster-coordinator.js.map +1 -0
  91. package/dist/src/storage/arachnode-fret-adapter.d.ts +65 -0
  92. package/dist/src/storage/arachnode-fret-adapter.d.ts.map +1 -0
  93. package/dist/src/storage/arachnode-fret-adapter.js +93 -0
  94. package/dist/src/storage/arachnode-fret-adapter.js.map +1 -0
  95. package/dist/src/storage/block-storage.d.ts +31 -0
  96. package/dist/src/storage/block-storage.d.ts.map +1 -0
  97. package/dist/src/storage/block-storage.js +154 -0
  98. package/dist/src/storage/block-storage.js.map +1 -0
  99. package/dist/src/storage/file-storage.d.ts +30 -0
  100. package/dist/src/storage/file-storage.d.ts.map +1 -0
  101. package/dist/src/storage/file-storage.js +127 -0
  102. package/dist/src/storage/file-storage.js.map +1 -0
  103. package/dist/src/storage/helpers.d.ts +3 -0
  104. package/dist/src/storage/helpers.d.ts.map +1 -0
  105. package/dist/src/storage/helpers.js +28 -0
  106. package/dist/src/storage/helpers.js.map +1 -0
  107. package/dist/src/storage/i-block-storage.d.ts +32 -0
  108. package/dist/src/storage/i-block-storage.d.ts.map +1 -0
  109. package/dist/src/storage/i-block-storage.js +2 -0
  110. package/dist/src/storage/i-block-storage.js.map +1 -0
  111. package/dist/src/storage/i-raw-storage.d.ts +20 -0
  112. package/dist/src/storage/i-raw-storage.d.ts.map +1 -0
  113. package/dist/src/storage/i-raw-storage.js +2 -0
  114. package/dist/src/storage/i-raw-storage.js.map +1 -0
  115. package/dist/src/storage/memory-storage.d.ts +27 -0
  116. package/dist/src/storage/memory-storage.d.ts.map +1 -0
  117. package/dist/src/storage/memory-storage.js +87 -0
  118. package/dist/src/storage/memory-storage.js.map +1 -0
  119. package/dist/src/storage/restoration-coordinator-v2.d.ts +63 -0
  120. package/dist/src/storage/restoration-coordinator-v2.d.ts.map +1 -0
  121. package/dist/src/storage/restoration-coordinator-v2.js +157 -0
  122. package/dist/src/storage/restoration-coordinator-v2.js.map +1 -0
  123. package/dist/src/storage/ring-selector.d.ts +56 -0
  124. package/dist/src/storage/ring-selector.d.ts.map +1 -0
  125. package/dist/src/storage/ring-selector.js +118 -0
  126. package/dist/src/storage/ring-selector.js.map +1 -0
  127. package/dist/src/storage/storage-monitor.d.ts +23 -0
  128. package/dist/src/storage/storage-monitor.d.ts.map +1 -0
  129. package/dist/src/storage/storage-monitor.js +40 -0
  130. package/dist/src/storage/storage-monitor.js.map +1 -0
  131. package/dist/src/storage/storage-repo.d.ts +17 -0
  132. package/dist/src/storage/storage-repo.d.ts.map +1 -0
  133. package/dist/src/storage/storage-repo.js +267 -0
  134. package/dist/src/storage/storage-repo.js.map +1 -0
  135. package/dist/src/storage/struct.d.ts +29 -0
  136. package/dist/src/storage/struct.d.ts.map +1 -0
  137. package/dist/src/storage/struct.js +2 -0
  138. package/dist/src/storage/struct.js.map +1 -0
  139. package/dist/src/sync/client.d.ts +27 -0
  140. package/dist/src/sync/client.d.ts.map +1 -0
  141. package/dist/src/sync/client.js +32 -0
  142. package/dist/src/sync/client.js.map +1 -0
  143. package/dist/src/sync/protocol.d.ts +58 -0
  144. package/dist/src/sync/protocol.d.ts.map +1 -0
  145. package/dist/src/sync/protocol.js +12 -0
  146. package/dist/src/sync/protocol.js.map +1 -0
  147. package/dist/src/sync/service.d.ts +62 -0
  148. package/dist/src/sync/service.d.ts.map +1 -0
  149. package/dist/src/sync/service.js +168 -0
  150. package/dist/src/sync/service.js.map +1 -0
  151. package/package.json +73 -0
  152. package/readme.md +497 -0
  153. package/src/cluster/client.ts +63 -0
  154. package/src/cluster/cluster-repo.ts +711 -0
  155. package/src/cluster/partition-detector.ts +158 -0
  156. package/src/cluster/service.ts +156 -0
  157. package/src/index.ts +30 -0
  158. package/src/it-utility.ts +36 -0
  159. package/src/libp2p-key-network.ts +334 -0
  160. package/src/libp2p-node.ts +335 -0
  161. package/src/logger.ts +9 -0
  162. package/src/network/get-network-manager.ts +17 -0
  163. package/src/network/network-manager-service.ts +334 -0
  164. package/src/peer-utils.ts +24 -0
  165. package/src/protocol-client.ts +54 -0
  166. package/src/repo/client.ts +112 -0
  167. package/src/repo/cluster-coordinator.ts +592 -0
  168. package/src/repo/coordinator-repo.ts +137 -0
  169. package/src/repo/redirect.ts +17 -0
  170. package/src/repo/service.ts +219 -0
  171. package/src/repo/types.ts +7 -0
  172. package/src/routing/libp2p-known-peers.ts +26 -0
  173. package/src/routing/responsibility.ts +63 -0
  174. package/src/routing/simple-cluster-coordinator.ts +70 -0
  175. package/src/storage/arachnode-fret-adapter.ts +128 -0
  176. package/src/storage/block-storage.ts +182 -0
  177. package/src/storage/file-storage.ts +163 -0
  178. package/src/storage/helpers.ts +29 -0
  179. package/src/storage/i-block-storage.ts +40 -0
  180. package/src/storage/i-raw-storage.ts +30 -0
  181. package/src/storage/memory-storage.ts +108 -0
  182. package/src/storage/restoration-coordinator-v2.ts +191 -0
  183. package/src/storage/ring-selector.ts +155 -0
  184. package/src/storage/storage-monitor.ts +59 -0
  185. package/src/storage/storage-repo.ts +320 -0
  186. package/src/storage/struct.ts +34 -0
  187. package/src/sync/client.ts +42 -0
  188. package/src/sync/protocol.ts +71 -0
  189. package/src/sync/service.ts +229 -0
package/readme.md ADDED
@@ -0,0 +1,497 @@
1
+ # Optimystic DB-P2P
2
+
3
+ A distributed peer-to-peer database system that provides concrete implementations of the Optimystic database abstractions using filesystem storage and libp2p networking. This package transforms the interfaces and abstractions from `@optimystic/db-core` into a fully operational distributed database system.
4
+
5
+ ## Overview
6
+
7
+ The `@optimystic/db-core` package provides abstractions and interfaces for database operations—immutable blocks, versioned transactions, repository interfaces, and collection data structures. However, it doesn't provide concrete implementations for storage or distribution. `db-p2p` provides concrete implementations of the core abstractions using:
8
+
9
+ - **Filesystem storage** with serialization for persistent, versioned block storage
10
+ - **libp2p networking** for decentralized peer-to-peer communication
11
+ - **Distributed consensus** using 2-phase commit protocols for consistency
12
+ - **Fault-tolerant coordination** with automatic recovery and data restoration
13
+
14
+ The result is a fully operational distributed database system that implements the interfaces defined in the core abstractions to provide a complete distributed database system.
15
+
16
+ ## Architecture Overview
17
+
18
+ The system provides three distinct communication interfaces, each serving different roles in the distributed architecture:
19
+
20
+ ```mermaid
21
+ graph TD
22
+ subgraph "External Client Process"
23
+ A[Application Code]
24
+ B[RepoClient]
25
+ A --> B
26
+ end
27
+
28
+ subgraph "Coordinator Node Process<br/>(Orchestrates Transactions)"
29
+ C[RepoService]
30
+ D[CoordinatorRepo]
31
+ E[ClusterClient]
32
+ F[StorageRepo]
33
+ subgraph "Local Storage"
34
+ F1[BlockStorage]
35
+ F2[FileRawStorage]
36
+ F3[Local Filesystem]
37
+ end
38
+ C --> D
39
+ D --> E
40
+ D --> F
41
+ F --> F1
42
+ F1 --> F2
43
+ F2 --> F3
44
+ end
45
+
46
+ subgraph "Cluster Peer 1 Process<br/>(Participates in Consensus)"
47
+ G1[ClusterService]
48
+ H1[ClusterMember]
49
+ I1[StorageRepo]
50
+ subgraph "Local Storage 1"
51
+ I1A[BlockStorage]
52
+ I1B[FileRawStorage]
53
+ I1C[Local Filesystem]
54
+ end
55
+ G1 --> H1
56
+ H1 --> I1
57
+ I1 --> I1A
58
+ I1A --> I1B
59
+ I1B --> I1C
60
+ end
61
+
62
+ subgraph "Cluster Peer 2 Process<br/>(Participates in Consensus)"
63
+ G2[ClusterService]
64
+ H2[ClusterMember]
65
+ I2[StorageRepo]
66
+ subgraph "Local Storage 2"
67
+ I2A[BlockStorage]
68
+ I2B[FileRawStorage]
69
+ I2C[Local Filesystem]
70
+ end
71
+ G2 --> H2
72
+ H2 --> I2
73
+ I2 --> I2A
74
+ I2A --> I2B
75
+ I2B --> I2C
76
+ end
77
+
78
+ subgraph "Cluster Peer N Process<br/>(Participates in Consensus)"
79
+ G3[ClusterService]
80
+ H3[ClusterMember]
81
+ I3[StorageRepo]
82
+ subgraph "Local Storage N"
83
+ I3A[BlockStorage]
84
+ I3B[FileRawStorage]
85
+ I3C[Local Filesystem]
86
+ end
87
+ G3 --> H3
88
+ H3 --> I3
89
+ I3 --> I3A
90
+ I3A --> I3B
91
+ I3B --> I3C
92
+ end
93
+
94
+ %% Network communication
95
+ B -.->|"/db-p2p/repo/1.0.0"| C
96
+ E -.->|"/db-p2p/cluster/1.0.0"| G1
97
+ E -.->|"/db-p2p/cluster/1.0.0"| G2
98
+ E -.->|"/db-p2p/cluster/1.0.0"| G3
99
+ ```
100
+
101
+ ### Repo Layer: External Client Interface
102
+
103
+ The repo layer provides the interface for external clients to communicate with the distributed database:
104
+
105
+ - **RepoClient**: Allows external clients to connect to any coordinator node
106
+ - **RepoService**: Handles incoming requests from external clients
107
+ - **CoordinatorRepo**: Orchestrates distributed transactions by coordinating with cluster peers
108
+ - **Network transparency**: Same `IRepo` interface whether local or distributed
109
+
110
+ ### Cluster Layer: Peer-to-Peer Coordination Interface
111
+
112
+ The cluster layer provides the interface for coordinators to communicate with other peers in the cluster:
113
+
114
+ - **ClusterClient**: Allows coordinators to send consensus requests to cluster peers
115
+ - **ClusterService**: Handles incoming consensus requests from coordinators
116
+ - **ClusterMember**: Implements 2-phase commit protocol for distributed consensus
117
+ - **Byzantine fault tolerance**: Ensures consistency even with peer failures
118
+
119
+ ### Storage Layer: Persistent Data Implementation
120
+
121
+ The storage layer provides concrete implementations of the core database abstractions:
122
+
123
+ - **StorageRepo**: Implements `IRepo` interface with filesystem-based persistence
124
+ - **BlockStorage**: Provides versioned block storage with conflict resolution
125
+ - **FileRawStorage**: JSON-based file storage with atomic operations
126
+ - **Data restoration**: Pluggable restoration for missing data from network peers
127
+
128
+ ## Detailed Component Architecture
129
+
130
+ ### Repo Layer Components
131
+
132
+ #### `RepoClient`
133
+ Allows external clients to connect to coordinator nodes:
134
+
135
+ ```typescript
136
+ class RepoClient extends ProtocolClient implements IRepo {
137
+ static create(peerId: PeerId, peerNetwork: IPeerNetwork): RepoClient
138
+ // Implements same IRepo interface as local storage
139
+ }
140
+ ```
141
+
142
+ **Key Features:**
143
+ - Network-transparent database operations for external clients
144
+ - Automatic protocol handling and message serialization
145
+ - Error handling for network failures and timeouts
146
+ - Connection pooling and optimization
147
+
148
+ #### `RepoService`
149
+ Handles incoming repository protocol messages from external clients:
150
+
151
+ ```typescript
152
+ class RepoService implements Startable {
153
+ // Protocol: /db-p2p/repo/1.0.0
154
+ // Transport: Length-prefixed JSON over libp2p streams
155
+ async start(): Promise<void>
156
+ async stop(): Promise<void>
157
+ }
158
+ ```
159
+
160
+ **Key Features:**
161
+ - Registers and handles the repository protocol
162
+ - Routes operations from external clients to coordinator implementation
163
+ - Manages concurrent connections and stream processing
164
+ - Provides comprehensive error handling and logging
165
+
166
+ #### `CoordinatorRepo`
167
+ Orchestrates distributed transactions by coordinating with cluster peers:
168
+
169
+ ```typescript
170
+ class CoordinatorRepo implements IRepo {
171
+ constructor(
172
+ keyNetwork: IKeyNetwork,
173
+ createClusterClient: (peerId: PeerId) => ClusterClient,
174
+ storageRepo: IRepo
175
+ )
176
+ }
177
+ ```
178
+
179
+ **Key Features:**
180
+ - Manages distributed transactions using cluster consensus
181
+ - Integrates with key network for peer discovery
182
+ - Uses cluster layer to coordinate with other peers
183
+ - Maintains local storage directly while coordinating remote operations
184
+
185
+ ### Cluster Layer Components
186
+
187
+ #### `ClusterClient`
188
+ Allows coordinators to send consensus requests to cluster peers:
189
+
190
+ ```typescript
191
+ class ClusterClient extends ProtocolClient implements ICluster {
192
+ async update(record: ClusterRecord): Promise<ClusterRecord>
193
+ }
194
+ ```
195
+
196
+ **Key Features:**
197
+ - Network communication for consensus operations
198
+ - Handles cluster record updates and responses
199
+ - Manages timeouts and retries for consensus requests
200
+
201
+ #### `ClusterService`
202
+ Handles incoming consensus requests from coordinators:
203
+
204
+ ```typescript
205
+ class ClusterService implements Startable {
206
+ // Protocol: /db-p2p/cluster/1.0.0
207
+ // Handles ClusterRecord updates for consensus
208
+ }
209
+ ```
210
+
211
+ **Key Features:**
212
+ - Registers and handles the cluster consensus protocol
213
+ - Routes consensus requests to local cluster member
214
+ - Manages concurrent consensus operations
215
+
216
+ #### `ClusterMember`
217
+ Implements 2-phase commit protocol for distributed consensus:
218
+
219
+ ```typescript
220
+ class ClusterMember implements ICluster {
221
+ async update(record: ClusterRecord): Promise<ClusterRecord>
222
+ // Handles: Promise collection → Majority consensus → Commit execution
223
+ }
224
+ ```
225
+
226
+ **Key Features:**
227
+ - Complete 2-phase commit protocol implementation
228
+ - Conflict detection and resolution
229
+ - Cryptographic signature verification
230
+ - Automatic timeout and cleanup management
231
+ - Uses storage layer to execute operations when consensus is reached
232
+
233
+ ### Storage Layer Components
234
+
235
+ #### `StorageRepo`
236
+ Implements `IRepo` interface with filesystem-based persistence:
237
+
238
+ ```typescript
239
+ class StorageRepo implements IRepo {
240
+ async get(blockGets: BlockGets): Promise<GetBlockResults>
241
+ async pend(request: PendRequest): Promise<PendResult>
242
+ async commit(request: CommitRequest): Promise<CommitResult>
243
+ async cancel(trxRef: TrxBlocks): Promise<void>
244
+ }
245
+ ```
246
+
247
+ **Key Features:**
248
+ - Concrete implementation of core database abstractions
249
+ - Orchestrates transactions across multiple blocks
250
+ - Handles revision conflicts and missing transaction detection
251
+ - Provides atomic commit operations with proper locking
252
+
253
+ #### `BlockStorage`
254
+ Provides versioned block storage with conflict resolution:
255
+
256
+ ```typescript
257
+ class BlockStorage implements IBlockStorage {
258
+ async getBlock(rev?: number): Promise<{ block: IBlock, actionRev: ActionRev }>
259
+ async savePendingAction(actionId: ActionId, transform: Transform): Promise<void>
260
+ async promotePendingAction(actionId: ActionId): Promise<void>
261
+ async ensureRevision(rev: number): Promise<void>
262
+ }
263
+ ```
264
+
265
+ **Key Features:**
266
+ - Maintains complete revision history for each block
267
+ - Reconstructs blocks by applying transforms to base versions
268
+ - Integrates with restoration callbacks for missing data
269
+ - Uses latches for thread-safe concurrent access
270
+
271
+ #### `FileRawStorage`
272
+ JSON-based file storage with atomic operations:
273
+
274
+ ```typescript
275
+ // File system organization
276
+ {basePath}/
277
+ ├── {blockId}/
278
+ │ ├── meta.json # Block metadata and revision ranges
279
+ │ ├── revs/{rev}.json # Revision → ActionId mappings
280
+ │ ├── pend/{actionId}.json # Pending actions
281
+ │ ├── trx/{actionId}.json # Committed actions
282
+ │ └── blocks/{actionId}.json # Materialized blocks
283
+ ```
284
+
285
+ **Key Features:**
286
+ - Concrete filesystem implementation of storage interfaces
287
+ - JSON serialization for cross-platform compatibility
288
+ - Atomic file operations for consistency
289
+ - Organized directory structure for efficient access
290
+
291
+ ## Integration Patterns
292
+
293
+ ### Relationship to `@optimystic/db-core`
294
+
295
+ The `db-p2p` package provides concrete implementations of the core database abstractions:
296
+
297
+ ```typescript
298
+ // Core provides interfaces and abstractions
299
+ import { IRepo, IBlock, Transform, IBlockStorage } from '@optimystic/db-core';
300
+
301
+ // P2P provides concrete implementations
302
+ class StorageRepo implements IRepo { /* filesystem-based repo */ }
303
+ class BlockStorage implements IBlockStorage { /* versioned block storage */ }
304
+ class RepoClient implements IRepo { /* network-transparent repo */ }
305
+ class CoordinatorRepo implements IRepo { /* distributed consensus repo */ }
306
+ ```
307
+
308
+ **Implementation Points:**
309
+ - **Storage Layer**: Provides concrete filesystem-based implementations of core interfaces
310
+ - **Network Layer**: Implements peer-to-peer communication using libp2p
311
+ - **Consensus Layer**: Adds distributed consensus while maintaining core interfaces
312
+ - **API Compatibility**: Same interfaces as core abstractions for seamless integration
313
+
314
+ ### Libp2p Integration
315
+
316
+ The package integrates deeply with libp2p for networking:
317
+
318
+ ```typescript
319
+ // Node creation with integrated services
320
+ const node = await createLibp2pNode({
321
+ services: {
322
+ repo: repoService({ protocol: '/db-p2p/repo/1.0.0' }),
323
+ cluster: clusterService({ protocol: '/db-p2p/cluster/1.0.0' })
324
+ }
325
+ });
326
+
327
+ // Key network integration
328
+ const keyNetwork = new Libp2pKeyPeerNetwork(node);
329
+ ```
330
+
331
+ **Integration Features:**
332
+ - **Protocol Management**: Registers custom protocols for repo and cluster operations
333
+ - **Stream Handling**: Uses libp2p streams for reliable message transport
334
+ - **Peer Discovery**: Integrates with libp2p DHT for peer discovery
335
+ - **Security**: Leverages libp2p's cryptographic peer identity
336
+
337
+ ## Usage Examples
338
+
339
+ ### Setting Up a Coordinator Node
340
+
341
+ ```typescript
342
+ import { createLibp2pNode } from '@optimystic/db-p2p';
343
+ import { repoService, clusterService, StorageRepo, CoordinatorRepo } from '@optimystic/db-p2p';
344
+
345
+ // Create a libp2p node with database services
346
+ const node = await createLibp2pNode({
347
+ services: {
348
+ repo: repoService(), // Handles external client requests
349
+ cluster: clusterService() // Handles peer coordination requests
350
+ }
351
+ });
352
+
353
+ // Set up storage layer with filesystem persistence
354
+ const storageRepo = new StorageRepo(/* filesystem config */);
355
+
356
+ // Set up coordinator that uses cluster layer for consensus
357
+ const coordinatorRepo = new CoordinatorRepo(
358
+ keyNetwork, // For peer discovery
359
+ createClusterClient, // For communicating with cluster peers
360
+ storageRepo // For local storage operations
361
+ );
362
+
363
+ // Start the node
364
+ await node.start();
365
+ ```
366
+
367
+ ### External Client Operations
368
+
369
+ ```typescript
370
+ // External clients connect to coordinator nodes
371
+ const client = RepoClient.create(coordinatorPeerId, peerNetwork);
372
+
373
+ // Operations work the same as core database interfaces
374
+ const blocks = await client.get({
375
+ blockIds: ['block1', 'block2'],
376
+ context: { rev: 10 }
377
+ });
378
+
379
+ // But automatically coordinate across the cluster
380
+ const pendResult = await client.pend({
381
+ actionId: 'tx1',
382
+ transforms: { block1: [/* operations */] },
383
+ rev: 11
384
+ });
385
+
386
+ const commitResult = await client.commit({
387
+ actionId: 'tx1',
388
+ blockIds: ['block1'],
389
+ rev: 11
390
+ });
391
+ ```
392
+
393
+ ### How Coordination Works
394
+
395
+ ```mermaid
396
+ sequenceDiagram
397
+ participant Client as External Client
398
+ participant RC as RepoClient
399
+ participant CR as CoordinatorRepo
400
+ participant CC as ClusterClient
401
+ participant CS as ClusterService
402
+ participant CM as ClusterMember
403
+ participant SR as StorageRepo
404
+
405
+ Client->>RC: pend(transaction)
406
+ RC->>CR: pend(transaction)
407
+ CR->>CC: consensus request
408
+ CC->>CS: cluster protocol
409
+ CS->>CM: update(ClusterRecord)
410
+ CM->>CM: 2-phase commit
411
+ CM->>SR: execute operation
412
+ SR-->>CM: result
413
+ CM-->>CS: consensus result
414
+ CS-->>CC: response
415
+ CC-->>CR: consensus complete
416
+ CR-->>RC: transaction result
417
+ RC-->>Client: pend result
418
+ ```
419
+
420
+ ## Documentation
421
+
422
+ For detailed information about specific components:
423
+
424
+ - **[Storage System](./docs/storage.md)**: Versioned block storage and persistence
425
+ - **[Repo Interface](./docs/repo.md)**: Distributed database operations
426
+ - **[Cluster Consensus](./docs/cluster.md)**: 2-phase commit and distributed consensus
427
+
428
+ ## Block Restoration & Arachnode Integration
429
+
430
+ The db-p2p package includes **dynamic Arachnode ring discovery** for automatic block restoration across storage tiers.
431
+
432
+ ### How Block Restoration Works
433
+
434
+ When a node is missing a block or revision, the restoration system:
435
+
436
+ 1. **Determines storage rings** - Nodes self-select ring depth based on capacity
437
+ 2. **Discovers peers via FRET** - Ring membership propagates via existing neighbor exchange
438
+ 3. **Queries rings intelligently** - Tries transaction ring first, then inner storage rings
439
+ 4. **Filters by partition** - Only queries peers responsible for the block's keyspace
440
+
441
+ ### Ring Selection
442
+
443
+ Nodes calculate their appropriate ring depth using:
444
+
445
+ ```
446
+ ringDepth = ceil(-log2(available_capacity / estimated_demand))
447
+ ```
448
+
449
+ **Examples:**
450
+ - 100% coverage → Ring 0 (full keyspace)
451
+ - 50% coverage → Ring 1 (2 partitions)
452
+ - 1% coverage → Ring 7 (128 partitions)
453
+
454
+ ### Architecture
455
+
456
+ ```
457
+ FRET (Pure DHT)
458
+ - Generic metadata transport
459
+ - Peer discovery & routing
460
+
461
+ ArachnodeFretAdapter (Plugin Layer)
462
+ - Arachnode-specific semantics
463
+ - Ring discovery methods
464
+
465
+ Restoration Components
466
+ - RingSelector: Capacity-based ring selection
467
+ - RestorationCoordinator: Multi-ring queries
468
+ - StorageMonitor: Capacity tracking
469
+ - SyncService/Client: Block request protocol
470
+ ```
471
+
472
+ ### Configuration
473
+
474
+ ```typescript
475
+ const node = await createLibp2pNode({
476
+ port: 9000,
477
+ networkName: 'mynet',
478
+ bootstrapNodes: ['...'],
479
+ clusterSize: 10, // Cluster size for peer discovery
480
+ arachnode: {
481
+ enableRingZulu: true // Default: enabled
482
+ }
483
+ });
484
+ ```
485
+
486
+ ### Ring Transitions
487
+
488
+ Nodes automatically transition between rings based on capacity thresholds:
489
+ - **Move OUT** (to more granular ring) when > 85% capacity used
490
+ - **Move IN** (to broader ring) when < 40% capacity used
491
+
492
+ ## Related Packages
493
+
494
+ - **[@optimystic/db-core](../db-core)**: Core database interfaces and local operations
495
+ - **[@optimystic/db-quereus](../db-quereus)**: Query engine and data access patterns
496
+ - **[p2p-fret](../fret)**: DHT implementation for peer discovery
497
+
@@ -0,0 +1,63 @@
1
+ import { type PeerId } from '@libp2p/interface';
2
+ import type { IPeerNetwork, ICluster, ClusterRecord } from '@optimystic/db-core';
3
+ import { ProtocolClient } from '../protocol-client.js';
4
+ import { peerIdFromString } from '@libp2p/peer-id';
5
+
6
+ export class ClusterClient extends ProtocolClient implements ICluster {
7
+ private constructor(peerId: PeerId, peerNetwork: IPeerNetwork, readonly protocolPrefix?: string) {
8
+ super(peerId, peerNetwork);
9
+ }
10
+
11
+ /** Create a new client instance */
12
+ public static create(peerId: PeerId, peerNetwork: IPeerNetwork, protocolPrefix?: string): ClusterClient {
13
+ return new ClusterClient(peerId, peerNetwork, protocolPrefix);
14
+ }
15
+
16
+ async update(record: ClusterRecord, hop: number = 0): Promise<ClusterRecord> {
17
+ const message = {
18
+ operation: 'update',
19
+ record
20
+ };
21
+ const preferred = (this.protocolPrefix ?? '/db-p2p') + '/cluster/1.0.0'
22
+ let response: any
23
+ try {
24
+ response = await this.processMessage<any>(message, preferred)
25
+ } catch (err) {
26
+ if (preferred !== '/db-p2p/cluster/1.0.0') {
27
+ response = await this.processMessage<any>(message, '/db-p2p/cluster/1.0.0')
28
+ } else {
29
+ throw err
30
+ }
31
+ }
32
+ if (response?.redirect?.peers?.length) {
33
+ if (hop >= 2) {
34
+ throw new Error('Redirect loop detected in ClusterClient (max hops reached)')
35
+ }
36
+ const currentIdStr = this.peerId.toString()
37
+ const next = response.redirect.peers.find((p: any) => p.id !== currentIdStr) ?? response.redirect.peers[0]
38
+ const nextId = peerIdFromString(next.id)
39
+ if (next.id === currentIdStr) {
40
+ throw new Error('Redirect loop detected in ClusterClient (same peer)')
41
+ }
42
+ this.recordCoordinatorForRecordIfSupported(record, nextId)
43
+ const nextClient = ClusterClient.create(nextId, this.peerNetwork, this.protocolPrefix)
44
+ return await nextClient.update(record, hop + 1)
45
+ }
46
+ return response as ClusterRecord;
47
+ }
48
+
49
+ private recordCoordinatorForRecordIfSupported(record: ClusterRecord, peerId: PeerId): void {
50
+ const rmsg: any = (record as any)?.message
51
+ let tailId: string | undefined
52
+ if (rmsg?.commit?.tailId) tailId = rmsg.commit.tailId
53
+ else if (rmsg?.pend?.transforms) {
54
+ const keys = Object.keys(rmsg.pend.transforms)
55
+ if (keys.length > 0) tailId = keys[0]
56
+ }
57
+ if (tailId) {
58
+ const kbytes = new TextEncoder().encode(tailId)
59
+ const pn: any = this.peerNetwork as any
60
+ if (typeof pn?.recordCoordinator === 'function') pn.recordCoordinator(kbytes, peerId)
61
+ }
62
+ }
63
+ }