protocol.hpp
1 // Cornell Protocol Types - C++ Implementation 2 // Matches NixServeCAS.Protocol.Types in Haskell 3 // 4 // PROOF CERTIFICATES: 5 // Types correspond to Cornell.Nix in Lean4 with: 6 // - WorkerOp toCode/fromCode roundtrip 7 // - ProtocolVersion encoding (major << 8 | minor) 8 9 #pragma once 10 11 #include <cstdint> 12 #include <optional> 13 #include <set> 14 #include <string> 15 #include <variant> 16 #include <vector> 17 18 namespace cornell { 19 20 // ═══════════════════════════════════════════════════════════════════════════════ 21 // Protocol Version 22 // PROOF: Cornell.Nix.ProtocolVersion 23 // ═══════════════════════════════════════════════════════════════════════════════ 24 25 struct ProtocolVersion { 26 uint64_t value; 27 28 constexpr ProtocolVersion() : value(0) {} 29 constexpr explicit ProtocolVersion(uint64_t v) : value(v) {} 30 31 // Create from major.minor 32 static constexpr ProtocolVersion make(uint64_t major, uint64_t minor) { 33 return ProtocolVersion((major << 8) | minor); 34 } 35 36 constexpr uint64_t major() const { return value >> 8; } 37 constexpr uint64_t minor() const { return value & 0xFF; } 38 39 // Check if version supports a feature introduced in minMinor 40 constexpr bool supports(uint64_t min_minor) const { 41 return minor() >= min_minor; 42 } 43 44 constexpr bool operator==(const ProtocolVersion& other) const { 45 return value == other.value; 46 } 47 constexpr bool operator<(const ProtocolVersion& other) const { 48 return value < other.value; 49 } 50 constexpr bool operator<=(const ProtocolVersion& other) const { 51 return value <= other.value; 52 } 53 constexpr bool operator>(const ProtocolVersion& other) const { 54 return value > other.value; 55 } 56 constexpr bool operator>=(const ProtocolVersion& other) const { 57 return value >= other.value; 58 } 59 }; 60 61 // Current protocol version (1.38) 62 constexpr ProtocolVersion CURRENT_PROTOCOL = ProtocolVersion::make(1, 38); 63 64 // Minimum supported version (1.10) 65 constexpr ProtocolVersion MINIMUM_PROTOCOL = ProtocolVersion::make(1, 10); 66 67 // ═══════════════════════════════════════════════════════════════════════════════ 68 // Worker Operations (all 28) 69 // PROOF: Cornell.Nix.WorkerOp 70 // ═══════════════════════════════════════════════════════════════════════════════ 71 72 enum class WorkerOp : uint64_t { 73 IsValidPath = 1, 74 HasSubstitutes = 3, 75 QueryPathHash = 4, 76 QueryReferences = 5, 77 QueryReferrers = 6, 78 AddToStore = 7, 79 AddTextToStore = 8, 80 BuildPaths = 9, 81 EnsurePath = 10, 82 AddTempRoot = 11, 83 AddIndirectRoot = 12, 84 SyncWithGC = 13, 85 FindRoots = 14, 86 ExportPath = 16, 87 QueryDeriver = 18, 88 SetOptions = 19, 89 CollectGarbage = 20, 90 QuerySubstitutablePathInfo = 21, 91 QueryDerivationOutputs = 22, 92 QueryAllValidPaths = 23, 93 QueryFailedPaths = 24, 94 ClearFailedPaths = 25, 95 QueryPathInfo = 26, 96 ImportPaths = 27, 97 QueryDerivationOutputNames = 28, 98 QueryPathFromHashPart = 29, 99 QuerySubstitutablePathInfos = 30, 100 QueryValidPaths = 31, 101 QuerySubstitutablePaths = 32, 102 QueryValidDerivers = 33, 103 OptimiseStore = 34, 104 VerifyStore = 35, 105 BuildDerivation = 36, 106 AddSignatures = 37, 107 NarFromPath = 38, 108 AddToStoreNar = 39, 109 QueryMissing = 40, 110 QueryDerivationOutputMap = 41, 111 RegisterDrvOutput = 42, 112 QueryRealisation = 43, 113 AddMultipleToStore = 44, 114 AddBuildLog = 45, 115 BuildPathsWithResults = 46, 116 }; 117 118 inline std::optional<WorkerOp> worker_op_from_code(uint64_t code) { 119 switch (code) { 120 case 1: return WorkerOp::IsValidPath; 121 case 3: return WorkerOp::HasSubstitutes; 122 case 4: return WorkerOp::QueryPathHash; 123 case 5: return WorkerOp::QueryReferences; 124 case 6: return WorkerOp::QueryReferrers; 125 case 7: return WorkerOp::AddToStore; 126 case 8: return WorkerOp::AddTextToStore; 127 case 9: return WorkerOp::BuildPaths; 128 case 10: return WorkerOp::EnsurePath; 129 case 11: return WorkerOp::AddTempRoot; 130 case 12: return WorkerOp::AddIndirectRoot; 131 case 13: return WorkerOp::SyncWithGC; 132 case 14: return WorkerOp::FindRoots; 133 case 16: return WorkerOp::ExportPath; 134 case 18: return WorkerOp::QueryDeriver; 135 case 19: return WorkerOp::SetOptions; 136 case 20: return WorkerOp::CollectGarbage; 137 case 21: return WorkerOp::QuerySubstitutablePathInfo; 138 case 22: return WorkerOp::QueryDerivationOutputs; 139 case 23: return WorkerOp::QueryAllValidPaths; 140 case 24: return WorkerOp::QueryFailedPaths; 141 case 25: return WorkerOp::ClearFailedPaths; 142 case 26: return WorkerOp::QueryPathInfo; 143 case 27: return WorkerOp::ImportPaths; 144 case 28: return WorkerOp::QueryDerivationOutputNames; 145 case 29: return WorkerOp::QueryPathFromHashPart; 146 case 30: return WorkerOp::QuerySubstitutablePathInfos; 147 case 31: return WorkerOp::QueryValidPaths; 148 case 32: return WorkerOp::QuerySubstitutablePaths; 149 case 33: return WorkerOp::QueryValidDerivers; 150 case 34: return WorkerOp::OptimiseStore; 151 case 35: return WorkerOp::VerifyStore; 152 case 36: return WorkerOp::BuildDerivation; 153 case 37: return WorkerOp::AddSignatures; 154 case 38: return WorkerOp::NarFromPath; 155 case 39: return WorkerOp::AddToStoreNar; 156 case 40: return WorkerOp::QueryMissing; 157 case 41: return WorkerOp::QueryDerivationOutputMap; 158 case 42: return WorkerOp::RegisterDrvOutput; 159 case 43: return WorkerOp::QueryRealisation; 160 case 44: return WorkerOp::AddMultipleToStore; 161 case 45: return WorkerOp::AddBuildLog; 162 case 46: return WorkerOp::BuildPathsWithResults; 163 default: return std::nullopt; 164 } 165 } 166 167 inline uint64_t worker_op_to_code(WorkerOp op) { 168 return static_cast<uint64_t>(op); 169 } 170 171 // ═══════════════════════════════════════════════════════════════════════════════ 172 // Trust Level 173 // ═══════════════════════════════════════════════════════════════════════════════ 174 175 enum class TrustLevel : uint64_t { 176 Unknown = 0, 177 Trusted = 1, 178 Untrusted = 2, 179 }; 180 181 // ═══════════════════════════════════════════════════════════════════════════════ 182 // Handshake Messages 183 // ═══════════════════════════════════════════════════════════════════════════════ 184 185 struct ClientHello { 186 uint64_t client_version; 187 }; 188 189 struct ServerHello { 190 uint64_t server_version; 191 }; 192 193 // ═══════════════════════════════════════════════════════════════════════════════ 194 // Features (version >= 1.38) 195 // ═══════════════════════════════════════════════════════════════════════════════ 196 197 enum class Feature { 198 ReapiV2, 199 CasSha256, 200 StreamingNar, 201 SignedNarinfo, 202 }; 203 204 // For unknown features, we use a separate type 205 struct UnknownFeature { 206 std::string name; 207 208 bool operator<(const UnknownFeature& other) const { 209 return name < other.name; 210 } 211 bool operator==(const UnknownFeature& other) const { 212 return name == other.name; 213 } 214 }; 215 216 using FeatureVariant = std::variant<Feature, UnknownFeature>; 217 218 inline std::string feature_to_text(const FeatureVariant& f) { 219 if (auto* known = std::get_if<Feature>(&f)) { 220 switch (*known) { 221 case Feature::ReapiV2: return "reapi-v2"; 222 case Feature::CasSha256: return "cas-sha256"; 223 case Feature::StreamingNar: return "streaming-nar"; 224 case Feature::SignedNarinfo: return "signed-narinfo"; 225 } 226 } 227 return std::get<UnknownFeature>(f).name; 228 } 229 230 inline FeatureVariant parse_feature(const std::string& text) { 231 if (text == "reapi-v2") return Feature::ReapiV2; 232 if (text == "cas-sha256") return Feature::CasSha256; 233 if (text == "streaming-nar") return Feature::StreamingNar; 234 if (text == "signed-narinfo") return Feature::SignedNarinfo; 235 return UnknownFeature{text}; 236 } 237 238 // ═══════════════════════════════════════════════════════════════════════════════ 239 // REAPI-v2 Types 240 // ═══════════════════════════════════════════════════════════════════════════════ 241 242 enum class DigestFunction { 243 SHA256 = 0, 244 SHA384 = 1, 245 SHA512 = 2, 246 }; 247 248 enum class Capability { 249 Execution, 250 ActionCache, 251 CAS, 252 Batch, 253 }; 254 255 struct ReapiConfig { 256 std::string instance_name; 257 DigestFunction digest_function; 258 std::set<Capability> capabilities; 259 }; 260 261 struct UpgradeOffer {}; 262 263 struct UpgradeResponse { 264 bool accept; 265 }; 266 267 // ═══════════════════════════════════════════════════════════════════════════════ 268 // Handshake Result 269 // ═══════════════════════════════════════════════════════════════════════════════ 270 271 struct HsResultNix { 272 ProtocolVersion version; 273 }; 274 275 struct HsResultReapi { 276 ReapiConfig config; 277 }; 278 279 using HandshakeResult = std::variant<HsResultNix, HsResultReapi>; 280 281 } // namespace cornell