Skip to content

5.1 Validation Framework and ProtocolLimits

Raul Cardenas Montoya edited this page Sep 19, 2026 · 1 revision

Validation Framework and ProtocolLimits

Relevant source files

The following files were used as context for generating this wiki page:

Purpose and Scope

This page details the validation framework implemented in src/validation/mod.rs, src/validation/bounded.rs, and src/validation/checks.rs. The validation layer enforces a fail-closed ingress contract for all public wire payloads, protecting memory and compute resources from malformed or malicious payloads without relying on untrusted serializer size hints.

Sources: src/validation/mod.rs:3-27(), src/validation/bounded.rs:1-12(), src/validation/checks.rs:1-9()


1. The Validate Trait and Contract

The validation framework revolves around the Validate trait defined in src/validation/mod.rs:89-97(). It exposes two methods:

  • validate(&self) -> Result<(), ValidationError>: Evaluates the payload against [ProtocolLimits::DEFAULT].
  • validate_with(&self, limits: ProtocolLimits) -> Result<(), ValidationError>: Evaluates the payload against custom resource boundaries.
graph TD
    IncomingPayload["Incoming Wire Payload"] --> Deserialization["Deserialization & bounded parsing"]
    Deserialization --> ValidateCall["Validate::validate() or validate_with()"]
    ValidateCall --> CheckLimits["ProtocolLimits Checks"]
    ValidateCall --> CheckValues["Finite & Range Checks"]
    CheckLimits --> ResultOK["Result::Ok(())"]
    CheckValues --> ResultOK
    CheckLimits --> ResultErr["Result::Err(ValidationError)"]
    CheckValues --> ResultErr

    classDef default fill:#fff,stroke:#000,stroke-width:1px;
Loading

Figure 1: Validation Execution Flow across Code Entities.

Sources: src/validation/mod.rs:88-97()


2. Resource Caps and ProtocolLimits

Resource bounds are governed by the ProtocolLimits struct (src/validation/mod.rs:47-64()). It defines explicit maximum thresholds for collections, strings, and aggregated records to prevent denial-of-service vectors via memory exhaustion.

Field Name Type Default Value Description
max_channel_values usize 65_536 Max length of stimulus values, embeddings, masks, gradient vectors, traces, and float arrays.
max_spike_events usize 65_536 Max length of SpikeBatch.spikes.
max_traces usize 65_536 Max length of TraceBatch.traces.
max_gradients usize 65_536 Max length of GradientBatch.gradients.
max_metadata_entries usize 256 Max keys in BatchMetadata.custom and ConfigPayload.config.
max_string_bytes usize 1_024 Max UTF-8 bytes for strings (session IDs, keys, values, source, layer ID).
max_aggregate_records usize 131_072 Max nested records aggregated inside one payload.

The associated constant ProtocolLimits::DEFAULT provides the standard pre-configured limits used by deserialization hooks (src/validation/mod.rs:71-80()).

Sources: src/validation/mod.rs:47-80()


3. Bounded Collection and String Deserialization Helpers

To prevent untrusted input from exploiting serde collection capacity hints, src/validation/bounded.rs implements explicit custom visitors. These reject sequences and maps immediately upon exceeding limits without trusting size_hint (src/validation/mod.rs:13-16()).

  • bounded_vec: Deserializes sequences up to a specified max item count, using reject_seq_overflow if limits are exceeded (src/validation/bounded.rs:82-126()).
  • bounded_opt_vec: Handles optional sequences with equivalent bounds enforcement (src/validation/bounded.rs:128-171()).
  • bounded_string: Deserializes strings, enforcing max UTF-8 byte length via StringVisitor (src/validation/bounded.rs:173-222()).
  • bounded_opt_string: Optional variant for bounded strings (src/validation/bounded.rs:224-240()).
graph TD
    DeserializerInput["Serde Deserializer Stream"] --> BoundedVec["bounded_vec() Visitor"]
    BoundedVec --> CheckSize{"Current Len >= Max?"}
    CheckSize -- Yes --> RejectOverflow["reject_seq_overflow() -> ValidationError::LimitExceeded"]
    CheckSize -- No --> PushItem["Push Element into Vec"]
    PushItem --> CheckMore{"More Elements?"}
    CheckMore -- Yes --> CheckSize
    CheckMore -- No --> ReturnVec["Return Vec<T>"]

    classDef default fill:#fff,stroke:#000,stroke-width:1px;
Loading

Figure 2: Sequence Deserialization Data Flow in bounded_vec.

Sources: src/validation/bounded.rs:13-126(), src/validation/mod.rs:11-16()


4. Finite-Value, Range, and Uniqueness Check Functions

src/validation/checks.rs provides primitive validation helper functions used during struct-level Validate::validate implementation calls:

  • check_string / check_opt_string: Validates that string length does not exceed limits.max_string_bytes (src/validation/checks.rs:10-34()).
  • check_count: Asserts that an actual count does not exceed a specified limit (src/validation/checks.rs:36-42()).
  • check_finite: Verifies that an f32 value is finite (value.is_finite()), raising a ValidationError::non_finite otherwise (src/validation/checks.rs:44-50()).
  • check_finite_slice: Iterates through an f32 slice, verifying each element's finiteness with indexed path formatting (src/validation/checks.rs:52-62()).
  • check_range: Combines finite checking with lower/upper bound assertions (src/validation/checks.rs:64-76()).
  • add_to_total: Safely accumulates aggregate record counts using checked arithmetic, rejecting overflows against max_aggregate_records (src/validation/checks.rs:78-96()).
  • check_unique_strings: Ensures uniqueness of key identifiers within collections (src/validation/checks.rs:121-137()).

Sources: src/validation/checks.rs:10-137()


5. Allocation Strategy and Fail-Closed Ingress Guarantees

The validation framework guarantees fail-closed semantics through strict deserialization boundaries:

  1. Size Hint Rejection: Serde deserializers ignore capacity hints provided by the wire payload if they exceed ProtocolLimits::DEFAULT (src/validation/mod.rs:13-16()).
  2. Overflow Detection: Sequences that exceed the maximum bound trigger an immediate parse error via IgnoredAny scan parsing (src/validation/bounded.rs:13-27()).
  3. Finite Checks: Non-finite floating-point values (NaN, +inf, -inf) are rejected across all tensor streams and readout configurations (src/validation/checks.rs:44-62()).

Sources: src/validation/mod.rs:11-26(), src/validation/bounded.rs:13-27(), src/validation/checks.rs:44-62()

Clone this wiki locally