/ cpp / include / cornell / protocol.hpp
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