// file: crates/ksp-store-api/src/model/raw_primitives.rs // version: 2 /// Maximum complete RAW account-data length admitted by the Store API. /// /// This is a Store admission guard, not a Solana protocol-size claim. pub const MAX_RAW_ACCOUNT_DATA_BYTES: usize = 16 * 1024 * 1024; /// Maximum UTF-8 byte length accepted for one safe logical RAW/provenance code. pub const MAX_RAW_CODE_BYTES: usize = 128; /// Maximum KSP-owned canonical RAW payload admitted by the Store API. /// /// This is a Store admission guard, not a Solana protocol-size claim. pub const MAX_RAW_PAYLOAD_BYTES: usize = 16 * 1024 * 1024; /// Maximum source-wire payload size recorded as acquisition metadata. /// /// The source payload itself is never retained by this metadata field. pub const MAX_RAW_SOURCE_PAYLOAD_BYTES: u64 = 64 * 1024 * 1024; /// Maximum supported Unix millisecond timestamp (`9999-12-31T23:59:59.999Z`). pub const MAX_RAW_UNIX_MILLIS: u64 = 253_402_300_799_999; /// Fixed-size digest identifying canonical or source bytes without retaining them. #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub struct RawContentHash([u8; 32]); impl RawContentHash { /// Creates one opaque 32-byte KSP content digest. #[must_use] pub const fn new(bytes: [u8; 32]) -> Self { return Self(bytes); } /// Returns the exact digest bytes. #[must_use] pub const fn as_bytes(&self) -> &[u8; 32] { return &self.0; } } impl std::fmt::Debug for RawContentHash { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { return formatter.write_str("RawContentHash(..)"); } } /// Stable deterministic idempotence key for one persisted acquisition observation. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct RawObservationKey([u8; 32]); impl RawObservationKey { /// Creates one producer-owned deterministic observation key. #[must_use] pub const fn new(bytes: [u8; 32]) -> Self { return Self(bytes); } /// Returns the exact observation-key bytes. #[must_use] pub const fn as_bytes(&self) -> &[u8; 32] { return &self.0; } } /// Canonical 64-byte Solana transaction signature used by Store identities. #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RawTransactionSignature([u8; 64]); impl RawTransactionSignature { /// Creates one canonical signature from already-decoded Solana signature bytes. #[must_use] pub const fn new(bytes: [u8; 64]) -> Self { return Self(bytes); } /// Returns the exact signature bytes. #[must_use] pub const fn as_bytes(&self) -> &[u8; 64] { return &self.0; } } impl std::fmt::Debug for RawTransactionSignature { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { return formatter.write_str("RawTransactionSignature(..)"); } } /// Bounded logical network/cluster identifier used in backend-independent Store identities. #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RawNetworkId(std::string::String); impl RawNetworkId { /// Creates one safe non-empty network/cluster identifier. pub fn new(value: impl std::convert::Into) -> ksp_core_lib::Result { let value = value.into(); if !valid_raw_code(value.as_str()) { return std::result::Result::Err(raw_model_error("network")); } return std::result::Result::Ok(Self(value)); } /// Returns the network/cluster identifier. #[must_use] pub fn as_str(&self) -> &str { return self.0.as_str(); } } /// Bounded logical code used by acquisition provenance fields. #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RawProvenanceCode(std::string::String); impl RawProvenanceCode { /// Creates one safe non-empty provenance code. pub fn new(value: impl std::convert::Into) -> ksp_core_lib::Result { let value = value.into(); if !valid_raw_code(value.as_str()) { return std::result::Result::Err(raw_provenance_error("code")); } return std::result::Result::Ok(Self(value)); } /// Returns the validated provenance code. #[must_use] pub fn as_str(&self) -> &str { return self.0.as_str(); } } /// Bounded identifier of one KSP-owned source-independent RAW persistence format. #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RawFormatId(std::string::String); impl RawFormatId { /// Creates one safe non-empty RAW format identifier. pub fn new(value: impl std::convert::Into) -> ksp_core_lib::Result { let value = value.into(); if !valid_raw_code(value.as_str()) { return std::result::Result::Err(raw_payload_error("format_id")); } return std::result::Result::Ok(Self(value)); } /// Returns the KSP-owned RAW format identifier. #[must_use] pub fn as_str(&self) -> &str { return self.0.as_str(); } } /// Bounded UTC timestamp represented as whole milliseconds since Unix epoch. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RawTimestamp { unix_millis: u64, } impl RawTimestamp { /// Creates a bounded UTC timestamp from Unix milliseconds. pub fn from_unix_millis(unix_millis: u64) -> ksp_core_lib::Result { if unix_millis > crate::MAX_RAW_UNIX_MILLIS { return std::result::Result::Err(raw_model_error("timestamp")); } return std::result::Result::Ok(Self { unix_millis }); } /// Returns whole milliseconds since Unix epoch. #[must_use] pub const fn unix_millis(&self) -> u64 { return self.unix_millis; } } /// Origin category describing why one acquisition was performed. #[non_exhaustive] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum RawAcquisitionOrigin { /// Historical acquisition intended to fill missing durable data. Backfill, /// Explicit import from a non-live source controlled by the caller. Import, /// Live acquisition from a currently active transport/session. Live, /// Explicit repair or reconciliation of previously known data. Repair, /// Explicit replay of an already-known source or archived acquisition. Replay, } /// Safe source-independent acquisition provenance attached to one persisted observation. #[derive(Clone, Debug, Eq, PartialEq)] pub struct RawAcquisitionProvenance { acquisition_method: crate::RawProvenanceCode, capture_session_id: std::option::Option, commitment: std::option::Option, endpoint_id: std::option::Option, filter_id: std::option::Option, observed_at: std::option::Option, origin: crate::RawAcquisitionOrigin, protocol: crate::RawProvenanceCode, provider: crate::RawProvenanceCode, received_at: crate::RawTimestamp, source_payload_hash: std::option::Option, source_payload_size_bytes: std::option::Option, } impl RawAcquisitionProvenance { /// Creates one successful acquisition provenance record with only mandatory safe metadata. #[must_use] pub fn new( provider: crate::RawProvenanceCode, protocol: crate::RawProvenanceCode, acquisition_method: crate::RawProvenanceCode, origin: crate::RawAcquisitionOrigin, received_at: crate::RawTimestamp, ) -> Self { return Self { acquisition_method, capture_session_id: std::option::Option::None, commitment: std::option::Option::None, endpoint_id: std::option::Option::None, filter_id: std::option::Option::None, observed_at: std::option::Option::None, origin, protocol, provider, received_at, source_payload_hash: std::option::Option::None, source_payload_size_bytes: std::option::Option::None, }; } /// Attaches one safe logical capture/session identifier. #[must_use] pub fn with_capture_session_id(mut self, value: crate::RawProvenanceCode) -> Self { self.capture_session_id = std::option::Option::Some(value); return self; } /// Attaches one safe commitment code captured at acquisition. #[must_use] pub fn with_commitment(mut self, value: crate::RawProvenanceCode) -> Self { self.commitment = std::option::Option::Some(value); return self; } /// Attaches one Config-owned logical endpoint identifier. #[must_use] pub fn with_endpoint_id(mut self, value: crate::RawProvenanceCode) -> Self { self.endpoint_id = std::option::Option::Some(value); return self; } /// Attaches one safe logical filter identifier. #[must_use] pub fn with_filter_id(mut self, value: crate::RawProvenanceCode) -> Self { self.filter_id = std::option::Option::Some(value); return self; } /// Attaches the source observation timestamp when it does not follow local receipt. pub fn try_with_observed_at(mut self, value: crate::RawTimestamp) -> ksp_core_lib::Result { if value > self.received_at { return std::result::Result::Err(raw_provenance_error("observed_at")); } self.observed_at = std::option::Option::Some(value); return std::result::Result::Ok(self); } /// Attaches the digest of source-specific bytes without retaining those bytes. #[must_use] pub fn with_source_payload_hash(mut self, value: crate::RawContentHash) -> Self { self.source_payload_hash = std::option::Option::Some(value); return self; } /// Attaches the bounded source-wire payload size. pub fn try_with_source_payload_size_bytes(mut self, value: u64) -> ksp_core_lib::Result { if value > crate::MAX_RAW_SOURCE_PAYLOAD_BYTES { return std::result::Result::Err(raw_provenance_error("source_payload_size_bytes")); } self.source_payload_size_bytes = std::option::Option::Some(value); return std::result::Result::Ok(self); } /// Returns the logical acquisition method code. #[must_use] pub const fn acquisition_method(&self) -> &crate::RawProvenanceCode { return &self.acquisition_method; } /// Returns the optional logical capture/session identifier. #[must_use] pub fn capture_session_id(&self) -> std::option::Option<&crate::RawProvenanceCode> { return self.capture_session_id.as_ref(); } /// Returns the optional commitment code captured at acquisition. #[must_use] pub fn commitment(&self) -> std::option::Option<&crate::RawProvenanceCode> { return self.commitment.as_ref(); } /// Returns the optional Config-owned logical endpoint identifier. #[must_use] pub fn endpoint_id(&self) -> std::option::Option<&crate::RawProvenanceCode> { return self.endpoint_id.as_ref(); } /// Returns the optional logical filter identifier. #[must_use] pub fn filter_id(&self) -> std::option::Option<&crate::RawProvenanceCode> { return self.filter_id.as_ref(); } /// Returns the optional source observation timestamp when the source supplies one. #[must_use] pub const fn observed_at(&self) -> std::option::Option { return self.observed_at; } /// Returns the acquisition origin category. #[must_use] pub const fn origin(&self) -> crate::RawAcquisitionOrigin { return self.origin; } /// Returns the logical transport/protocol code. #[must_use] pub fn protocol(&self) -> &crate::RawProvenanceCode { return &self.protocol; } /// Returns the safe provider code. #[must_use] pub fn provider(&self) -> &crate::RawProvenanceCode { return &self.provider; } /// Returns the local receipt timestamp. #[must_use] pub const fn received_at(&self) -> crate::RawTimestamp { return self.received_at; } /// Returns the optional digest of source-specific bytes without retaining those bytes. #[must_use] pub const fn source_payload_hash(&self) -> std::option::Option { return self.source_payload_hash; } /// Returns the optional source-wire payload size. #[must_use] pub const fn source_payload_size_bytes(&self) -> std::option::Option { return self.source_payload_size_bytes; } } /// Bounded source-independent KSP RAW persistence payload. pub struct RawPayload { bytes: std::boxed::Box<[u8]>, content_hash: crate::RawContentHash, format_id: crate::RawFormatId, format_version: u32, } impl RawPayload { /// Creates one canonical RAW payload after enforcing Store-owned admission invariants. /// /// The supplied bytes must already use the KSP-owned source-independent format identified /// by `format_id` and `format_version`; this constructor performs no transport conversion. pub fn try_new( format_id: crate::RawFormatId, format_version: u32, bytes: std::boxed::Box<[u8]>, content_hash: crate::RawContentHash, ) -> ksp_core_lib::Result { if format_version == 0 { return std::result::Result::Err(raw_payload_error("format_version")); } if bytes.is_empty() || bytes.len() > crate::MAX_RAW_PAYLOAD_BYTES { return std::result::Result::Err( raw_payload_error("bytes") .with_context("actual_len", bytes.len().to_string()) .with_context("maximum_len", crate::MAX_RAW_PAYLOAD_BYTES.to_string()), ); } return std::result::Result::Ok(Self { bytes, content_hash, format_id, format_version }); } /// Returns the canonical RAW bytes without transport/provider interpretation. #[must_use] pub fn bytes(&self) -> &[u8] { return self.bytes.as_ref(); } /// Returns the deterministic content digest supplied for these exact canonical bytes. #[must_use] pub const fn content_hash(&self) -> crate::RawContentHash { return self.content_hash; } /// Returns the KSP-owned source-independent format identifier. #[must_use] pub fn format_id(&self) -> &crate::RawFormatId { return &self.format_id; } /// Returns the KSP-owned format version. #[must_use] pub const fn format_version(&self) -> u32 { return self.format_version; } /// Returns the canonical payload length in bytes. #[must_use] pub fn byte_len(&self) -> usize { return self.bytes.len(); } } impl std::fmt::Debug for RawPayload { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { return formatter .debug_struct("RawPayload") .field("format_id", &self.format_id) .field("format_version", &self.format_version) .field("len", &self.bytes.len()) .field("content_hash", &self.content_hash) .finish(); } } fn raw_model_error(field: &'static str) -> ksp_core_lib::Error { return ksp_core_lib::Error::new(crate::ERROR_CODE_RAW_MODEL_INVALID, "invalid backend-agnostic RAW Store model").with_context("field", field); } fn raw_payload_error(field: &'static str) -> ksp_core_lib::Error { return ksp_core_lib::Error::new(crate::ERROR_CODE_RAW_PAYLOAD_INVALID, "invalid KSP RAW persistence payload").with_context("field", field); } fn raw_provenance_error(field: &'static str) -> ksp_core_lib::Error { return ksp_core_lib::Error::new(crate::ERROR_CODE_RAW_PROVENANCE_INVALID, "invalid RAW acquisition provenance").with_context("field", field); } fn valid_raw_code(value: &str) -> bool { if value.is_empty() || value.len() > crate::MAX_RAW_CODE_BYTES { return false; } return value.bytes().all(|byte| return byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-' | b'.' | b':')); } #[cfg(test)] #[path = "../../unit_tests/model/raw_primitives.rs"] mod tests;