Files
lattice/docs/roadmap.md
T

6.0 KiB

Lattice Roadmap

Milestone 1: Single-Node Append-Only Log

Goal: A single node can create, sign, and persist entries to its own log. No networking yet.

Deliverables

  • HLC timestamps
  • Node identity (Ed25519 keypair, save/load)
  • Entry signing & verification
  • Log file I/O (append, read, hash verification)
  • SigChain (validate entries before appending)
  • Store (redb) — kv + meta tables, log replay
  • Interactive CLI: init, put, get, delete, status, quit

Success Criteria

  • Can create a new identity
  • Can append entries to local log
  • Can replay log to reconstruct KV state
  • All operations survive restart

Multi-KV Refactoring (before M2) ✓

  • DataDir → stores/{uuid}/ subdirectories
  • Store → per-store state.db
  • Log paths → stores/{uuid}/logs/{author}.log
  • Proto: Entry has store_id (UUID)
  • CLI → init, create-store, list-stores, use
  • meta.db stores table (MetaStore)
  • SigChain → validate entry.store_id

Milestone 1.5: DAG Conflict Resolution

Goal: Upgrade store from simple LWW to DAG-based conflict resolution per architecture.md.

Deliverables

  • Proto: Add repeated bytes parent_hashes to Entry (for DAG causality)
  • Proto: Add HeadInfo message for multi-head storage
  • Store: KV table schema → Vec<u8> → Vec<HeadInfo>
  • Store: apply_entry → track multiple heads, merge parent tips
  • Store: get → deterministic winner (highest HLC, author tiebreaker)
  • Store: get_heads → inspect all heads for a key
  • EntryBuilder: .parent_hashes(...) method for DAG ancestry
  • CLI: Show conflict indicator when multiple heads

Success Criteria

  • Concurrent writes to same key create multiple heads
  • Reads return deterministic winner
  • Next write citing both heads merges fork to single tip
  • All existing tests still pass (71 tests)

Milestone 1.9: Async Refactor

Goal: Prepare codebase for concurrent CLI + network operation.

Deliverables

Phase 1: Store Actor (sync)

  • Store actor pattern: dedicated thread owns Store, receives commands via std::sync::mpsc
  • StoreHandle wraps channel sender, keeps current API
  • Validate: CLI works as before with actor

Phase 2: Async Runtime

  • Add tokio runtime (#[tokio::main])
  • Migrate std::sync::mpsctokio::sync::mpsc
  • Async CLI using block_in_place for sync handlers

Success Criteria

  • CLI still works as before
  • Store operations serialized (no data races)
  • Ready for concurrent network tasks

Milestone 2: Two-Node Sync

Goal: Two nodes can sync their logs over the network.

Deliverables

Phase 1: Sync Logic (no network)

  • SyncState with AuthorInfo (seq + hash) for hash-based log resumption
  • Store::sync_state() → author-to-seq+hash map from AUTHOR_TABLE
  • SyncState::diff()Vec<MissingRange> with from_hash for read_entries_after
  • Multi-store sync test: compute diff, fetch entries, apply, verify same state

Phase 2: Iroh Integration

Completed:

  • Node info in root store on init: /nodes/{pubkey}/info + /status
  • CLI: invite <pubkey> to authorize peers
  • CLI: peers to list known nodes (with name/added_at info, sorted)
  • CLI: remove <pubkey> to remove a peer
  • Iroh endpoint on startup (same Ed25519 key, mDNS + DNS discovery)
  • CLI: join <nodeid> - connects to peer, verifies invited
  • Peer verification via /nodes/{pubkey}/status check

Join Protocol (new→existing):

  • Proto: JoinRequest / JoinResponse with store UUID
  • Accept handler sends root store UUID in response
  • Join command creates empty store with received UUID (no writes until sync)

Sync Protocol (bidirectional):

  • Proto: PeerMessage wrapper with oneof for message type discrimination
  • framing.rs with MessageSink/MessageStream using LengthDelimitedCodec
  • Proto: SyncRequest/SyncResponse using SyncState
  • Store::read_entries_after(hash) to fetch log chunks
  • Accept handler: receive SyncState, compute diff, send missing entries
  • Sync command: receive entries, apply to store via apply_entry
  • CLI: sync [nodeid] command (syncs with all active peers if no nodeid)
  • After sync: node updates own /nodes/{pubkey}/info with hostname

Cleanup:

  • Move core logic from cmd_join and cmd_sync out of commands.rs (now in sync.rs)
  • Add 'invited' state: invite sets 'invited', peer sets 'active' after sync

Regressions:

  • Entry ordering: Per-author streaming is correct (hash chain per author, HLC for cross-author).
  • Multi-head sync fixed: SyncState now tracks HashSet of head hashes per author.
  • Sync entry ordering: Entries sent in HLC order (merge-sort across authors) to ensure causal order.

Background Sync:

  • Periodic sync with known peers
  • Track last sync time per peer

Success Criteria

  • Node A writes, Node B syncs, both have same state
  • Works offline-first (sync when connected)

Post-M2 Refactoring:

  • Unify node.rs from lattice-cli and lattice-core
  • Use prost for node status in store

Milestone 3: Multi-Node Mesh

Goal: N nodes form a gossip mesh with watermark consensus.

Deliverables

  • Gossip protocol
  • Watermark tracking & log pruning
  • Node invitation (sigchain membership)
  • Conflict detection (LWW resolution)

Future

  • Mobile (iOS/Android) clients
  • Key rotation
  • Secure storage (Keychain, TPM)
  • Snapshots for fast bootstrap
  • FUSE filesystem mount
    • Note: FUSE requires u64 inode numbers → maintain BiMap<u64, Hash> in redb
  • Merkle-ized State
    • state.db as Merkle tree with signed root hash
    • O(1) sync checks (compare root), efficient binary-search diffing
    • Light clients: fetch value + Merkle proof, verify without full state
    • Trade-off: write amplification, requires deterministic tree (Patricia Trie / Merkle Search Tree)