The Critical Transition: From Single to Repeated Vanilla Proofs

Message Overview

In message [msg 290], the assistant performs a targeted code read of cuzk-server/src/service.rs, the gRPC service implementation that bridges protobuf request definitions to core engine types. The message captures a pivotal moment in the Phase 1 implementation of the cuzk proving daemon — the point where accumulated research crystallizes into a concrete code change plan. The assistant writes:

Now let me look at the proto for the current SubmitProofRequest — the vanilla_proof field is a single bytes. For PoSt and SnapDeals we need repeated bytes for multiple vanilla proofs. Let me check how the current service maps proto to core types.

It then reads the full contents of service.rs, examining every line of the gRPC service implementation.

Why This Message Was Written: The Reasoning and Motivation

This message sits at a critical juncture in the Phase 1 implementation. The assistant has completed an extensive research phase spanning three prior messages:

How Decisions Were Made

While this message does not itself make implementation decisions, it sets the stage for the decisions that follow in [msg 291] (the actual implementation chunk). The reading of service.rs reveals several critical design properties:

  1. The mapping is straightforward: The service.rs file shows a clean impl ProvingEngine for GrpcService with a submit_proof method that converts protobuf types to core types via a From impl or direct field access. The current code maps vanilla_proof directly as a single Vec<u8>.
  2. The ProofRequest type already has a vanilla_proofs field: Reading the core types in [msg 286] revealed that types.rs already defines vanilla_proofs: Vec<Vec<u8>> — a vector of byte vectors. This is a forward-looking design choice: the core type was already prepared for multiple proofs, but the protobuf layer and the service mapping still used the single-proof model. This means the protobuf change is the bottleneck.
  3. The error handling pattern is clear: The service uses Status::invalid_argument and Status::internal for error cases, a pattern that must be preserved when adding new proof types.
  4. The registered_proof enum mapping is critical: The service maps protobuf enum values to the RegisteredProof type, which in turn maps to the FFI RegisteredSealProof enum via #[repr(i32)]. Any new proof type must correctly pass through this chain. These observations inform the decision to: (a) change the protobuf vanilla_proof field from bytes to repeated bytes, (b) update the service mapping to pass through the vector, and (c) add new registered_proof enum values for the three new proof types.

Assumptions Made by the User or Agent

Several assumptions underpin this message:

  1. The protobuf schema is the single source of truth for the API contract: The assistant assumes that changing the protobuf definition and regenerating the Rust code will be sufficient to update the entire API surface. This is correct given the tonic/prost codegen setup, but it implicitly assumes that no other consumers of the protobuf (e.g., the Go client in Curio) will break — a reasonable assumption since Curio's Go code is the intended consumer and will be updated in tandem.
  2. The current single-proof design is a limitation, not a feature: The assistant assumes that PoRep's single-vanilla-proof model was a simplification and that the multi-proof model is the correct generalization. This is validated by the research in [msg 288], which showed that Curio's Go FFI layer already handles multiple vanilla proofs for PoSt.
  3. The core type system is stable: The assistant assumes that types.rs with its vanilla_proofs: Vec<Vec<u8>> field is the correct target and that no further type changes are needed. This assumption holds for Phase 1 but may need revisiting if proof types with different metadata requirements emerge.
  4. The mapping pattern in service.rs is the right one to extend: The assistant assumes that the current pattern of protobuf-to-core-type conversion in submit_proof is the correct pattern to follow for the new proof types. This is a safe assumption given the clean separation of concerns.

Mistakes or Incorrect Assumptions

No significant mistakes are present in this message itself — it is a read-only operation. However, a subtle incorrect assumption lurks in the framing: the assistant states that "For PoSt and SnapDeals we need repeated bytes for multiple vanilla proofs." While this is true for PoSt (which has one vanilla proof per sector, potentially many sectors per request), SnapDeals actually uses a different pattern. The SnapDeals proof (also called EmptySectorUpdate) requires three commitment CIDs as inputs, not multiple vanilla proofs. The assistant's research in [msg 288] correctly identified this distinction — SnapDeals needs commitment_a, commitment_b, and commitment_c fields — but the message here groups PoSt and SnapDeals together under the "repeated bytes" umbrella. This is a minor imprecision: PoSt needs repeated vanilla proofs, while SnapDeals needs multiple commitment fields (which are semantically different from vanilla proofs). The assistant's later implementation in [msg 291] correctly handles this distinction, so the imprecision is corrected before any code is written.

Input Knowledge Required

To fully understand this message, one needs:

  1. The protobuf schema context: The current SubmitProofRequest uses a single bytes vanilla_proof field, adequate for PoRep but not for multi-proof types. This was established in [msg 289].
  2. The core type system: The ProofRequest struct in cuzk-core/src/types.rs already defines vanilla_proofs: Vec<Vec<u8>> — a vector of byte vectors — anticipating the multi-proof future. This was discovered in [msg 286].
  3. The API signatures for PoSt and SnapDeals: From [msg 287], the assistant knows that generate_winning_post_with_vanilla takes vanilla_proofs: &[Vec<u8>] (a slice of byte vectors), generate_single_window_post_with_vanilla similarly takes multiple vanilla proofs, and generate_empty_sector_update_proof_with_vanilla takes three separate commitment parameters.
  4. The Curio Go FFI data flow: From [msg 288], the assistant knows that Curio generates one vanilla proof per sector for PoSt and serializes them as a concatenated byte stream with length prefixes, which the FFI layer deserializes back into individual proofs.
  5. The gRPC service pattern: Understanding how tonic services map protobuf messages to Rust types, including the Request/Response wrapper and the Status error type.

Output Knowledge Created

This message produces several important outputs:

  1. A verified mapping baseline: The assistant now knows exactly how service.rs converts protobuf SubmitProofRequest into core ProofRequest. The code is clean and follows a simple pattern: extract fields from the protobuf message, construct the core type, and submit to the engine.
  2. Identification of change points: The assistant can now identify precisely which lines of service.rs need modification: the vanilla_proof extraction (single bytes -> repeated bytes), the registered_proof handling (new enum values), and the addition of commitment fields for SnapDeals.
  3. Confirmation of the extension strategy: The core type already uses Vec<Vec<u8>> for vanilla proofs, so the protobuf change is the only missing piece. The service mapping is straightforward enough to extend without refactoring.
  4. A validated architecture: The separation between protobuf types (in cuzk-proto), core types (in cuzk-core), and service mapping (in cuzk-server) is clean and maintainable. Changes to the API surface can be isolated to the protobuf definition and the service mapping layer.

The Thinking Process Visible in Reasoning

The assistant's reasoning follows a systematic, research-driven methodology:

Step 1 — Gap identification: The assistant identifies that the current protobuf schema uses a single bytes field for vanilla proofs, which cannot represent the multiple vanilla proofs required by PoSt and SnapDeals. This gap was identified by comparing the protobuf schema (read in [msg 289]) with the API signatures (read in [msg 287]).

Step 2 — Impact assessment: Before making any changes, the assistant needs to understand the full impact. It reads service.rs to see how the protobuf maps to core types. This is a classic "measure twice, cut once" approach — understand the existing code before modifying it.

Step 3 — Pattern recognition: The assistant reads the entire service.rs file, not just the relevant lines. This reveals the full pattern: how errors are handled, how the registered_proof enum is mapped, how the response is constructed. Understanding the full pattern ensures that new code will be consistent with existing code.

Step 4 — Forward reference: The assistant is already thinking about the implementation. By noting that "the vanilla_proof field is a single bytes" and that "we need repeated bytes", the assistant is mentally preparing the protobuf schema change. The read of service.rs answers the question: "What else needs to change if I update the protobuf?"

This thinking process reveals a developer who is methodical, thorough, and resistant to premature implementation. Rather than diving directly into code changes, the assistant invests time in understanding the existing system's structure, ensuring that the changes will integrate cleanly and correctly.

Broader Significance in the Phase 1 Context

This message, though brief, represents the critical transition from research to implementation in the Phase 1 workflow. The prior messages were purely investigative — reading code, exploring APIs, understanding data flows. This message is the first that explicitly frames a change that needs to be made: "we need repeated bytes for multiple vanilla proofs." The read of service.rs is the final piece of research before the assistant begins writing code.

In the broader arc of the cuzk project, this moment is where the abstract design of "support all four Filecoin proof types" becomes concrete: the assistant has identified the exact protobuf field that must change, the exact file that must be modified, and the exact pattern that must be followed. The implementation that follows in [msg 291] — touching six files across four crates — flows directly from the understanding gained in this message.

The message also exemplifies a key engineering principle: when extending a system, first understand the existing extension points. The assistant discovered that the core type system already anticipated multi-proof support (via Vec<Vec<u8>>), meaning the protobuf layer was the only bottleneck. This discovery — that the core was already prepared — is a direct result of the systematic code reading approach and significantly simplifies the implementation.