syntax = "proto3"; package lattice; // 1. The Wrapper (What flies over the wire) message SignedEntry { // The serialized bytes of the 'Entry' message. // We keep this as raw bytes so the signature verification is stable. bytes entry_bytes = 1; // Ed25519 Signature of 'entry_bytes' bytes signature = 2; // Public Key of the author (32 bytes) bytes author_id = 3; } // 2. The Log Entry (The Atomic Unit) message Entry { // Versioning allows us to change the format radically later if needed uint32 version = 1; // Store this entry belongs to (16-byte UUID) bytes store_id = 6; // Ordering Metadata bytes prev_hash = 2; // Link to previous sigchain entry (32 bytes) uint64 seq = 3; // Monotonic sequence number HLC timestamp = 4; // Hybrid Logical Clock // DAG ancestry: hashes of entries this supersedes (separate from sigchain) repeated bytes parent_hashes = 7; // The Batch of Operations repeated Operation ops = 5; } // HeadInfo: a tip/head in the DAG for a key message HeadInfo { bytes value = 1; // The value at this head uint64 hlc = 2; // Combined HLC for ordering (wall_time_ms << 16 | counter) bytes author = 3; // Author's public key (32 bytes) bytes hash = 4; // Hash of the SignedEntry that created this head bool tombstone = 5; // True if this head represents a delete } // HeadList: wrapper for storing multiple heads per key in state.db message HeadList { repeated HeadInfo heads = 1; } // AuthorState: tracks last applied entry per author for replay optimization message AuthorState { uint64 seq = 1; // Last applied seq for this author's sigchain bytes hash = 2; // Hash of last applied entry uint64 log_offset = 3; // Byte offset in log file for fast resume } // Hybrid Logical Clock message HLC { uint64 wall_time = 1; // Unix timestamp (ms) uint32 counter = 2; // Logical counter for same-ms ordering } // 3. The Operation (The Change) message Operation { // "oneof" is how Protobuf handles Rust Enums oneof op_type { PutOp put = 1; DeleteOp delete = 2; // Future: MergeOp merge = 3; } } message PutOp { bytes key = 1; bytes value = 2; } message DeleteOp { bytes key = 1; } // 4. The Sync Handshake (Vector Clocks) message SyncState { repeated Frontier frontiers = 1; HLC sender_hlc = 2; // Sender's current clock (for peer time awareness) } message Frontier { bytes author_id = 1; // Ed25519 public key (32 bytes) uint64 max_seq = 2; // Highest sequence number seen from this author repeated bytes head_hashes = 3; // All head hashes for this author } // 5. Log File Record (wrapper for storage) message LogRecord { bytes hash = 1; // BLAKE3 hash of entry_bytes (32 bytes) bytes entry_bytes = 2; // Serialized SignedEntry } // 6. Join Protocol Messages (new node joining existing mesh) message JoinRequest { bytes node_pubkey = 1; // Joining node's public key (32 bytes) } message JoinResponse { bytes store_uuid = 1; // Root store UUID (16 bytes) for new node to create bytes inviter_pubkey = 2; // Inviter's public key for verification } // 7. Sync Protocol Messages (bidirectional sync after join) message SyncRequest { SyncState state = 1; // Sender's sync state (for incremental sync) bool full_sync = 2; // If true, request all entries (for join) } message SyncResponse { SyncState state = 1; // Responder's sync state } message SyncEntry { bytes signed_entry = 1; // Serialized SignedEntry bytes hash = 2; // Hash for verification } message SyncDone { uint64 entries_sent = 1; } // 8. Peer Message Wrapper (for proper message type discrimination) message PeerMessage { oneof message { JoinRequest join_request = 1; JoinResponse join_response = 2; SyncRequest sync_request = 3; SyncResponse sync_response = 4; SyncEntry sync_entry = 5; SyncDone sync_done = 6; } }