v0.3.8-pre.003
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-api/src/capability/raw_account.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
/// Read capability for complete canonical RAW account states.
|
||||
///
|
||||
@@ -24,6 +24,20 @@ pub trait RawAccountStateRead: std::marker::Send + std::marker::Sync {
|
||||
) -> crate::StoreApiFuture<'a, crate::Result<crate::RawPage<crate::RawAccountStateReference>>>;
|
||||
}
|
||||
|
||||
/// Read capability for data-free random-access RAW account-state inspection.
|
||||
///
|
||||
/// This capability is intended for bounded operator/admin inspection. It must
|
||||
/// return exact logical counts and summaries only; complete account bytes stay
|
||||
/// behind [`RawAccountStateRead::get_raw_account_state`]. Worker, replay and
|
||||
/// backfill traversal continue to use the opaque-cursor list operation.
|
||||
pub trait RawAccountStateInspectionRead: std::marker::Send + std::marker::Sync {
|
||||
/// Inspects one random-access account-state window with exact logical counts.
|
||||
fn inspect_raw_account_states<'a>(
|
||||
&'a self,
|
||||
query: &'a crate::RawAccountStateInspectionQuery,
|
||||
) -> crate::StoreApiFuture<'a, crate::Result<crate::RawInspectionPage<crate::RawAccountStateSummary>>>;
|
||||
}
|
||||
|
||||
/// Write capability for complete RAW account-state acquisitions.
|
||||
///
|
||||
/// The account state and its acquisition observation form one logical
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-api/src/capability/raw_transaction.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
/// Read capability for canonical RAW transactions.
|
||||
///
|
||||
@@ -24,6 +24,20 @@ pub trait RawTransactionRead: std::marker::Send + std::marker::Sync {
|
||||
) -> crate::StoreApiFuture<'a, crate::Result<crate::RawPage<crate::RawTransactionReference>>>;
|
||||
}
|
||||
|
||||
/// Read capability for payload-free random-access RAW transaction inspection.
|
||||
///
|
||||
/// This capability is intended for bounded operator/admin inspection. It must
|
||||
/// return exact logical counts and summaries only; canonical payload bytes stay
|
||||
/// behind [`RawTransactionRead::get_raw_transaction`]. Worker, replay and
|
||||
/// backfill traversal continue to use the opaque-cursor list operation.
|
||||
pub trait RawTransactionInspectionRead: std::marker::Send + std::marker::Sync {
|
||||
/// Inspects one random-access transaction window with exact logical counts.
|
||||
fn inspect_raw_transactions<'a>(
|
||||
&'a self,
|
||||
query: &'a crate::RawTransactionInspectionQuery,
|
||||
) -> crate::StoreApiFuture<'a, crate::Result<crate::RawInspectionPage<crate::RawTransactionSummary>>>;
|
||||
}
|
||||
|
||||
/// Write capability for canonical RAW transaction acquisitions.
|
||||
///
|
||||
/// The transaction and its acquisition observation form one logical persistence
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-api/src/lib.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
@@ -26,6 +26,8 @@ pub use self::capability::StoreApiFuture;
|
||||
pub use self::capability::raw_account::RawAccountObservationRead;
|
||||
/// Write capability for additional observations of already persisted RAW account states.
|
||||
pub use self::capability::raw_account::RawAccountObservationWrite;
|
||||
/// Read capability for data-free random-access RAW account-state inspection.
|
||||
pub use self::capability::raw_account::RawAccountStateInspectionRead;
|
||||
/// Read capability for complete canonical RAW account states.
|
||||
pub use self::capability::raw_account::RawAccountStateRead;
|
||||
/// Write capability for complete canonical RAW account-state acquisitions.
|
||||
@@ -34,6 +36,8 @@ pub use self::capability::raw_account::RawAccountStateWrite;
|
||||
pub use self::capability::raw_retention::RawTransactionRetentionRead;
|
||||
/// Write capability for policy-authorized RAW transaction retention transitions.
|
||||
pub use self::capability::raw_retention::RawTransactionRetentionWrite;
|
||||
/// Read capability for payload-free random-access RAW transaction inspection.
|
||||
pub use self::capability::raw_transaction::RawTransactionInspectionRead;
|
||||
/// Read capability for persisted RAW transaction observations.
|
||||
pub use self::capability::raw_transaction::RawTransactionObservationRead;
|
||||
/// Write capability for additional observations of already persisted RAW transactions.
|
||||
@@ -60,6 +64,18 @@ pub use self::model::raw_account::RawAccountObservation;
|
||||
pub use self::model::raw_account::RawAccountState;
|
||||
/// Durable backend-independent identity of one canonical RAW account state.
|
||||
pub use self::model::raw_account::RawAccountStateReference;
|
||||
/// Backend-independent random-access inspection query for RAW account states.
|
||||
pub use self::model::raw_inspection::RawAccountStateInspectionQuery;
|
||||
/// Data-free summary of one canonical RAW account state for operator inspection.
|
||||
pub use self::model::raw_inspection::RawAccountStateSummary;
|
||||
/// One bounded random-access inspection page with exact logical counts.
|
||||
pub use self::model::raw_inspection::RawInspectionPage;
|
||||
/// Random-access page request dedicated to bounded interactive RAW inspection.
|
||||
pub use self::model::raw_inspection::RawInspectionPageRequest;
|
||||
/// Backend-independent random-access inspection query for RAW transactions.
|
||||
pub use self::model::raw_inspection::RawTransactionInspectionQuery;
|
||||
/// Payload-free summary of one canonical RAW transaction for operator inspection.
|
||||
pub use self::model::raw_inspection::RawTransactionSummary;
|
||||
/// Combined outcome of one atomic canonical RAW entity plus observation acquisition.
|
||||
pub use self::model::raw_outcome::RawAcquisitionWriteOutcome;
|
||||
/// Outcome for one canonical RAW entity in an idempotent persistence operation.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-api/src/model.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Private home for persistent Store models.
|
||||
//!
|
||||
@@ -9,6 +9,7 @@
|
||||
//! one or more models.
|
||||
|
||||
pub(crate) mod raw_account;
|
||||
pub(crate) mod raw_inspection;
|
||||
pub(crate) mod raw_outcome;
|
||||
pub(crate) mod raw_pagination;
|
||||
pub(crate) mod raw_primitives;
|
||||
|
||||
366
crates/ksp-store-api/src/model/raw_inspection.rs
Normal file
366
crates/ksp-store-api/src/model/raw_inspection.rs
Normal file
@@ -0,0 +1,366 @@
|
||||
// file: crates/ksp-store-api/src/model/raw_inspection.rs
|
||||
// version: 1
|
||||
|
||||
/// Random-access page request dedicated to bounded interactive RAW inspection.
|
||||
///
|
||||
/// This request is intentionally distinct from [`crate::RawPageRequest`]. It
|
||||
/// provides offset/limit semantics for operator-facing inspection while the
|
||||
/// canonical RAW list APIs keep their opaque backend cursors for replay,
|
||||
/// backfill and worker traversal.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct RawInspectionPageRequest {
|
||||
limit: crate::RawPageLimit,
|
||||
offset: u64,
|
||||
}
|
||||
|
||||
impl RawInspectionPageRequest {
|
||||
/// Creates one inspection request from an absolute zero-based offset and positive page limit.
|
||||
#[must_use]
|
||||
pub const fn new(offset: u64, limit: crate::RawPageLimit) -> Self {
|
||||
return Self { limit, offset };
|
||||
}
|
||||
|
||||
/// Returns the exact caller-requested page size.
|
||||
#[must_use]
|
||||
pub const fn limit(&self) -> crate::RawPageLimit {
|
||||
return self.limit;
|
||||
}
|
||||
|
||||
/// Returns the absolute zero-based item offset within the filtered result set.
|
||||
#[must_use]
|
||||
pub const fn offset(&self) -> u64 {
|
||||
return self.offset;
|
||||
}
|
||||
}
|
||||
|
||||
/// One bounded random-access inspection page with exact logical counts.
|
||||
///
|
||||
/// `total_items` is the exact count inside the mandatory query scope before
|
||||
/// optional filters. `filtered_items` is the exact count after optional query
|
||||
/// filters. The item vector contains only the requested page window.
|
||||
#[derive(Debug)]
|
||||
pub struct RawInspectionPage<T> {
|
||||
filtered_items: u64,
|
||||
items: std::vec::Vec<T>,
|
||||
total_items: u64,
|
||||
}
|
||||
|
||||
impl<T> RawInspectionPage<T> {
|
||||
/// Creates one inspection page after validating count consistency.
|
||||
pub fn try_new(items: std::vec::Vec<T>, total_items: u64, filtered_items: u64) -> crate::Result<Self> {
|
||||
if filtered_items > total_items {
|
||||
return std::result::Result::Err(raw_model_error("filtered_items"));
|
||||
}
|
||||
let item_count = u64::try_from(items.len());
|
||||
let item_count = match item_count {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(raw_model_error("items")),
|
||||
};
|
||||
if item_count > filtered_items {
|
||||
return std::result::Result::Err(raw_model_error("items"));
|
||||
}
|
||||
return std::result::Result::Ok(Self { filtered_items, items, total_items });
|
||||
}
|
||||
|
||||
/// Returns the exact count after optional query filters.
|
||||
#[must_use]
|
||||
pub const fn filtered_items(&self) -> u64 {
|
||||
return self.filtered_items;
|
||||
}
|
||||
|
||||
/// Returns the current inspection page items.
|
||||
#[must_use]
|
||||
pub fn items(&self) -> &[T] {
|
||||
return self.items.as_slice();
|
||||
}
|
||||
|
||||
/// Consumes the page and returns its bounded inspection items.
|
||||
#[must_use]
|
||||
pub fn into_items(self) -> std::vec::Vec<T> {
|
||||
return self.items;
|
||||
}
|
||||
|
||||
/// Returns the exact count before optional query filters inside the mandatory scope.
|
||||
#[must_use]
|
||||
pub const fn total_items(&self) -> u64 {
|
||||
return self.total_items;
|
||||
}
|
||||
}
|
||||
|
||||
/// Backend-independent random-access inspection query for RAW transactions.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RawTransactionInspectionQuery {
|
||||
direction: crate::RawSortDirection,
|
||||
network: crate::RawNetworkId,
|
||||
page: crate::RawInspectionPageRequest,
|
||||
slots: crate::RawSlotRange,
|
||||
}
|
||||
|
||||
impl RawTransactionInspectionQuery {
|
||||
/// Creates one transaction inspection query.
|
||||
#[must_use]
|
||||
pub fn new(network: crate::RawNetworkId, slots: crate::RawSlotRange, direction: crate::RawSortDirection, page: crate::RawInspectionPageRequest) -> Self {
|
||||
return Self { direction, network, page, slots };
|
||||
}
|
||||
|
||||
/// Returns the requested deterministic traversal direction.
|
||||
#[must_use]
|
||||
pub const fn direction(&self) -> crate::RawSortDirection {
|
||||
return self.direction;
|
||||
}
|
||||
|
||||
/// Returns the mandatory logical network scope.
|
||||
#[must_use]
|
||||
pub fn network(&self) -> &crate::RawNetworkId {
|
||||
return &self.network;
|
||||
}
|
||||
|
||||
/// Returns the random-access inspection page request.
|
||||
#[must_use]
|
||||
pub const fn page(&self) -> crate::RawInspectionPageRequest {
|
||||
return self.page;
|
||||
}
|
||||
|
||||
/// Returns optional inclusive slot filters.
|
||||
#[must_use]
|
||||
pub const fn slots(&self) -> crate::RawSlotRange {
|
||||
return self.slots;
|
||||
}
|
||||
}
|
||||
|
||||
/// Backend-independent random-access inspection query for RAW account states.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RawAccountStateInspectionQuery {
|
||||
direction: crate::RawSortDirection,
|
||||
network: crate::RawNetworkId,
|
||||
page: crate::RawInspectionPageRequest,
|
||||
pubkey: std::option::Option<crate::Pubkey>,
|
||||
slots: crate::RawSlotRange,
|
||||
}
|
||||
|
||||
impl RawAccountStateInspectionQuery {
|
||||
/// Creates one account-state inspection query.
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
network: crate::RawNetworkId,
|
||||
pubkey: std::option::Option<crate::Pubkey>,
|
||||
slots: crate::RawSlotRange,
|
||||
direction: crate::RawSortDirection,
|
||||
page: crate::RawInspectionPageRequest,
|
||||
) -> Self {
|
||||
return Self { direction, network, page, pubkey, slots };
|
||||
}
|
||||
|
||||
/// Returns the requested deterministic traversal direction.
|
||||
#[must_use]
|
||||
pub const fn direction(&self) -> crate::RawSortDirection {
|
||||
return self.direction;
|
||||
}
|
||||
|
||||
/// Returns the mandatory logical network scope.
|
||||
#[must_use]
|
||||
pub fn network(&self) -> &crate::RawNetworkId {
|
||||
return &self.network;
|
||||
}
|
||||
|
||||
/// Returns the random-access inspection page request.
|
||||
#[must_use]
|
||||
pub const fn page(&self) -> crate::RawInspectionPageRequest {
|
||||
return self.page;
|
||||
}
|
||||
|
||||
/// Returns an optional exact account-address filter.
|
||||
#[must_use]
|
||||
pub fn pubkey(&self) -> std::option::Option<&crate::Pubkey> {
|
||||
return self.pubkey.as_ref();
|
||||
}
|
||||
|
||||
/// Returns optional inclusive slot filters.
|
||||
#[must_use]
|
||||
pub const fn slots(&self) -> crate::RawSlotRange {
|
||||
return self.slots;
|
||||
}
|
||||
}
|
||||
|
||||
/// Payload-free summary of one canonical RAW transaction for operator inspection.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RawTransactionSummary {
|
||||
block_time: std::option::Option<crate::RawTimestamp>,
|
||||
content_hash: crate::RawContentHash,
|
||||
format_id: crate::RawFormatId,
|
||||
format_version: u32,
|
||||
payload_size_bytes: std::option::Option<u64>,
|
||||
reference: crate::RawTransactionReference,
|
||||
retention_state: crate::RawRetentionState,
|
||||
slot: u64,
|
||||
}
|
||||
|
||||
impl RawTransactionSummary {
|
||||
/// Creates one payload-free transaction summary after validating summary invariants.
|
||||
pub fn try_new(
|
||||
reference: crate::RawTransactionReference,
|
||||
slot: u64,
|
||||
block_time: std::option::Option<crate::RawTimestamp>,
|
||||
format_id: crate::RawFormatId,
|
||||
format_version: u32,
|
||||
content_hash: crate::RawContentHash,
|
||||
payload_size_bytes: std::option::Option<u64>,
|
||||
retention_state: crate::RawRetentionState,
|
||||
) -> crate::Result<Self> {
|
||||
if format_version == 0 {
|
||||
return std::result::Result::Err(raw_model_error("format_version"));
|
||||
}
|
||||
if let std::option::Option::Some(size) = payload_size_bytes {
|
||||
let size = usize::try_from(size);
|
||||
let size = match size {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(raw_model_error("payload_size_bytes")),
|
||||
};
|
||||
if size == 0 || size > crate::MAX_RAW_PAYLOAD_BYTES {
|
||||
return std::result::Result::Err(raw_model_error("payload_size_bytes"));
|
||||
}
|
||||
}
|
||||
if retention_state == crate::RawRetentionState::Purged {
|
||||
if payload_size_bytes.is_some() {
|
||||
return std::result::Result::Err(raw_model_error("payload_size_bytes"));
|
||||
}
|
||||
} else if payload_size_bytes.is_none() {
|
||||
return std::result::Result::Err(raw_model_error("payload_size_bytes"));
|
||||
}
|
||||
return std::result::Result::Ok(Self {
|
||||
block_time,
|
||||
content_hash,
|
||||
format_id,
|
||||
format_version,
|
||||
payload_size_bytes,
|
||||
reference,
|
||||
retention_state,
|
||||
slot,
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the optional canonical block timestamp.
|
||||
#[must_use]
|
||||
pub const fn block_time(&self) -> std::option::Option<crate::RawTimestamp> {
|
||||
return self.block_time;
|
||||
}
|
||||
|
||||
/// Returns the deterministic canonical content digest.
|
||||
#[must_use]
|
||||
pub const fn content_hash(&self) -> crate::RawContentHash {
|
||||
return self.content_hash;
|
||||
}
|
||||
|
||||
/// Returns the KSP-owned canonical RAW format identifier.
|
||||
#[must_use]
|
||||
pub fn format_id(&self) -> &crate::RawFormatId {
|
||||
return &self.format_id;
|
||||
}
|
||||
|
||||
/// Returns the KSP-owned canonical RAW format version.
|
||||
#[must_use]
|
||||
pub const fn format_version(&self) -> u32 {
|
||||
return self.format_version;
|
||||
}
|
||||
|
||||
/// Returns the canonical payload size when payload content is logically retained.
|
||||
#[must_use]
|
||||
pub const fn payload_size_bytes(&self) -> std::option::Option<u64> {
|
||||
return self.payload_size_bytes;
|
||||
}
|
||||
|
||||
/// Returns the durable backend-independent transaction identity.
|
||||
#[must_use]
|
||||
pub fn reference(&self) -> &crate::RawTransactionReference {
|
||||
return &self.reference;
|
||||
}
|
||||
|
||||
/// Returns the logical RAW transaction retention state.
|
||||
#[must_use]
|
||||
pub const fn retention_state(&self) -> crate::RawRetentionState {
|
||||
return self.retention_state;
|
||||
}
|
||||
|
||||
/// Returns the Solana slot containing the transaction.
|
||||
#[must_use]
|
||||
pub const fn slot(&self) -> u64 {
|
||||
return self.slot;
|
||||
}
|
||||
}
|
||||
|
||||
/// Data-free summary of one canonical RAW account state for operator inspection.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RawAccountStateSummary {
|
||||
data_length_bytes: u64,
|
||||
executable: bool,
|
||||
lamports: u64,
|
||||
owner: crate::Pubkey,
|
||||
reference: crate::RawAccountStateReference,
|
||||
rent_epoch: u64,
|
||||
}
|
||||
|
||||
impl RawAccountStateSummary {
|
||||
/// Creates one data-free account-state summary after validating its bounded data length.
|
||||
pub fn try_new(
|
||||
reference: crate::RawAccountStateReference,
|
||||
lamports: u64,
|
||||
owner: crate::Pubkey,
|
||||
executable: bool,
|
||||
rent_epoch: u64,
|
||||
data_length_bytes: u64,
|
||||
) -> crate::Result<Self> {
|
||||
let data_length = usize::try_from(data_length_bytes);
|
||||
let data_length = match data_length {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::result::Result::Err(raw_model_error("data_length_bytes")),
|
||||
};
|
||||
if data_length > crate::MAX_RAW_ACCOUNT_DATA_BYTES {
|
||||
return std::result::Result::Err(raw_model_error("data_length_bytes"));
|
||||
}
|
||||
return std::result::Result::Ok(Self { data_length_bytes, executable, lamports, owner, reference, rent_epoch });
|
||||
}
|
||||
|
||||
/// Returns the complete canonical account-data length without exposing account bytes.
|
||||
#[must_use]
|
||||
pub const fn data_length_bytes(&self) -> u64 {
|
||||
return self.data_length_bytes;
|
||||
}
|
||||
|
||||
/// Returns whether the account is executable.
|
||||
#[must_use]
|
||||
pub const fn executable(&self) -> bool {
|
||||
return self.executable;
|
||||
}
|
||||
|
||||
/// Returns the account lamport balance.
|
||||
#[must_use]
|
||||
pub const fn lamports(&self) -> u64 {
|
||||
return self.lamports;
|
||||
}
|
||||
|
||||
/// Returns the account owner program public key.
|
||||
#[must_use]
|
||||
pub const fn owner(&self) -> &crate::Pubkey {
|
||||
return &self.owner;
|
||||
}
|
||||
|
||||
/// Returns the durable backend-independent account-state identity.
|
||||
#[must_use]
|
||||
pub fn reference(&self) -> &crate::RawAccountStateReference {
|
||||
return &self.reference;
|
||||
}
|
||||
|
||||
/// Returns the rent epoch reported for this account state.
|
||||
#[must_use]
|
||||
pub const fn rent_epoch(&self) -> u64 {
|
||||
return self.rent_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
fn raw_model_error(field: &'static str) -> crate::Error {
|
||||
return crate::Error::new(crate::ERROR_CODE_RAW_MODEL_INVALID, "invalid backend-agnostic RAW inspection model").with_context("field", field);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../../unit_tests/model/raw_inspection.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user