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`], [`ChildObjectResolver`], and [`RpcIndexes`] (all
6//! impl'd in sibling modules) into the top-level trait
7//! `sui-rpc-api` consumes.
8//!
9//! Adds three 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//! - [`get_struct_layout_with_overlay`]: delegates to the
22//!   [`resolve_struct_layout`] shim in `layout.rs`.
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::full_checkpoint_content::ObjectSet;
29use sui_types::messages_checkpoint::CheckpointSequenceNumber;
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 get_struct_layout_with_overlay(
74        &self,
75        struct_tag: &move_core_types::language_storage::StructTag,
76        overlay: &ObjectSet,
77    ) -> StorageResult<Option<move_core_types::annotated_value::MoveTypeLayout>> {
78        self.resolve_struct_layout(struct_tag, overlay)
79    }
80}