sui_rpc_store/reader/state_reader.rs
1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! [`RpcStateReader`] rollup — composes [`ObjectStore`],
5//! [`ReadStore`], [`RuntimeObjectResolver`], and [`RpcIndexes`] (all
6//! impl'd in sibling modules) into the top-level trait
7//! `sui-rpc-api` consumes.
8//!
9//! Adds rpc-api-specific entry points:
10//!
11//! - [`get_lowest_available_checkpoint_objects`]: returns the
12//! pruning watermark's `tx_seq_lo`-derived checkpoint floor. We
13//! reuse `pruning_watermark.checkpoint_lo` for now — the rpc-api
14//! trait distinguishes "checkpoint data available" from "object
15//! data available" but in this store both axes prune together.
16//! - [`get_chain_identifier`]: reads any pipeline's recorded chain
17//! id from the framework's `__chain_id` CF (every pipeline
18//! records the same chain id on first contact).
19//! - [`indexes`]: returns `Some(self)` so callers reach the
20//! [`RpcIndexes`] impl through the same handle.
21//! - [`layout_package_store`]: supplies the package source in `layout.rs`
22//! for response-local layout resolution.
23
24use sui_consistent_store::FrameworkSchema;
25use sui_consistent_store::reader::Reader;
26use sui_types::digests::ChainIdentifier;
27use sui_types::digests::CheckpointDigest;
28use sui_types::messages_checkpoint::CheckpointSequenceNumber;
29use sui_types::storage::BackingPackageStore;
30use sui_types::storage::RpcIndexes;
31use sui_types::storage::RpcStateReader;
32use sui_types::storage::error::Error as StorageError;
33use sui_types::storage::error::Result as StorageResult;
34
35use crate::reader::RpcStoreReader;
36
37impl<R: Reader + Send + Sync> RpcStateReader for RpcStoreReader<R> {
38 fn get_lowest_available_checkpoint_objects(&self) -> StorageResult<CheckpointSequenceNumber> {
39 // Object availability tracks the same pruning watermark
40 // axis as checkpoint availability in this store; both
41 // CFs are pruned together by `pruning_watermark`.
42 let watermarks = self
43 .schema()
44 .get_pruning_watermarks()
45 .map_err(StorageError::custom)?
46 .unwrap_or_default();
47 Ok(watermarks.checkpoint_lo)
48 }
49
50 fn get_chain_identifier(&self) -> StorageResult<ChainIdentifier> {
51 // The framework's `__chain_id` CF has one entry per
52 // pipeline, every entry agreeing on the same chain id.
53 // Take the first row we see.
54 let framework = FrameworkSchema::new(self.db().clone());
55 let first = framework
56 .chain_ids
57 .iter(..)
58 .map_err(StorageError::custom)?
59 .next();
60 let Some(entry) = first else {
61 return Err(StorageError::missing(
62 "no chain id recorded — no pipeline has observed a checkpoint yet",
63 ));
64 };
65 let (_, chain_id) = entry.map_err(StorageError::custom)?;
66 Ok(ChainIdentifier::from(CheckpointDigest::new(chain_id.0)))
67 }
68
69 fn indexes(&self) -> Option<&dyn RpcIndexes> {
70 Some(self)
71 }
72
73 fn layout_package_store(&self) -> Box<dyn BackingPackageStore + Send + Sync + '_> {
74 Box::new(super::layout::PackageStoreOverObjects {
75 schema: self.schema(),
76 })
77 }
78}