Skip to main content

sui_indexer_alt_jsonrpc/api/objects/
mod.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use filter::SuiObjectResponseQuery;
5use futures::future;
6use jsonrpsee::core::RpcResult;
7use jsonrpsee::proc_macros::rpc;
8use mysten_common::ZipDebugEqIteratorExt;
9use sui_json_rpc_types::Page;
10use sui_json_rpc_types::SuiGetPastObjectRequest;
11use sui_json_rpc_types::SuiObjectDataOptions;
12use sui_json_rpc_types::SuiObjectResponse;
13use sui_json_rpc_types::SuiPastObjectResponse;
14use sui_types::base_types::ObjectID;
15use sui_types::base_types::SequenceNumber;
16use sui_types::base_types::SuiAddress;
17
18use crate::api::objects::error::Error;
19use crate::api::rpc_module::RpcModule;
20use crate::context::Context;
21use crate::error::InternalContext;
22use crate::error::invalid_params;
23
24mod error;
25pub(crate) mod filter;
26pub(crate) mod response;
27
28#[rpc(server, namespace = "sui")]
29trait ObjectsApi {
30    /// Return the object information for the latest version of an object.
31    #[method(name = "getObject")]
32    async fn get_object(
33        &self,
34        // The ID of the queried obect
35        object_id: ObjectID,
36        // Options for specifying the content to be returned
37        options: Option<SuiObjectDataOptions>,
38    ) -> RpcResult<SuiObjectResponse>;
39
40    /// Return the object information for the latest versions of multiple objects.
41    #[method(name = "multiGetObjects")]
42    async fn multi_get_objects(
43        &self,
44        // the IDs of the queried objects
45        object_ids: Vec<ObjectID>,
46        // Options for specifying the content to be returned
47        options: Option<SuiObjectDataOptions>,
48    ) -> RpcResult<Vec<SuiObjectResponse>>;
49
50    /// Return the object information for a specified version.
51    ///
52    /// Note that past versions of an object may be pruned from the system, even if they once
53    /// existed. Different RPC services may return different responses for the same request as a
54    /// result, based on their pruning policies.
55    #[method(name = "tryGetPastObject")]
56    async fn try_get_past_object(
57        &self,
58        // The ID of the queried object
59        object_id: ObjectID,
60        // The version of the queried object.
61        version: SequenceNumber,
62        // Options for specifying the content to be returned
63        options: Option<SuiObjectDataOptions>,
64    ) -> RpcResult<SuiPastObjectResponse>;
65
66    /// Return the object information for multiple specified objects and versions.
67    ///
68    /// Note that past versions of an object may be pruned from the system, even if they once
69    /// existed. Different RPC services may return different responses for the same request as a
70    /// result, based on their pruning policies.
71    #[method(name = "tryMultiGetPastObjects")]
72    async fn try_multi_get_past_objects(
73        &self,
74        // A vector of object and versions to be queried
75        past_objects: Vec<SuiGetPastObjectRequest>,
76        // Options for specifying the content to be returned
77        options: Option<SuiObjectDataOptions>,
78    ) -> RpcResult<Vec<SuiPastObjectResponse>>;
79}
80
81#[rpc(server, namespace = "suix")]
82trait QueryObjectsApi {
83    /// Query objects by their owner's address. Returns a paginated list of objects.
84    ///
85    /// If a cursor is provided, the query will start from the object after the one pointed to by
86    /// this cursor, otherwise pagination starts from the first page of objects owned by the
87    /// address.
88    ///
89    /// The definition of "first" page is somewhat arbitrary. It is a page such that continuing to
90    /// paginate an address's objects from this page will eventually reach all objects owned by
91    /// that address assuming that the owned object set does not change. If the owned object set
92    /// does change, pagination may not be consistent (may not reflect a set of objects that the
93    /// address owned at a single point in time).
94    ///
95    /// The size of each page is controlled by the `limit` parameter.
96    #[method(name = "getOwnedObjects")]
97    async fn get_owned_objects(
98        &self,
99        // The owner's address.
100        address: SuiAddress,
101        // Additional querying criteria for the object.
102        query: Option<SuiObjectResponseQuery>,
103        // Cursor to start paginating from.
104        cursor: Option<String>,
105        // Maximum number of objects to return per page.
106        limit: Option<usize>,
107    ) -> RpcResult<Page<SuiObjectResponse, String>>;
108}
109
110pub(crate) struct Objects(pub Context);
111
112pub(crate) struct QueryObjects(pub Context);
113
114#[async_trait::async_trait]
115impl ObjectsApiServer for Objects {
116    async fn get_object(
117        &self,
118        object_id: ObjectID,
119        options: Option<SuiObjectDataOptions>,
120    ) -> RpcResult<SuiObjectResponse> {
121        let Self(ctx) = self;
122        let options = options.unwrap_or_default();
123        Ok(response::live_object(ctx, object_id, &options)
124            .await
125            .with_internal_context(|| {
126                format!("Failed to get object {object_id} at latest version")
127            })?)
128    }
129
130    async fn multi_get_objects(
131        &self,
132        object_ids: Vec<ObjectID>,
133        options: Option<SuiObjectDataOptions>,
134    ) -> RpcResult<Vec<SuiObjectResponse>> {
135        let Self(ctx) = self;
136        let config = &ctx.config().objects;
137        if object_ids.len() > config.max_multi_get_objects {
138            return Err(invalid_params(Error::TooManyKeys {
139                requested: object_ids.len(),
140                max: config.max_multi_get_objects,
141            })
142            .into());
143        }
144
145        let options = options.unwrap_or_default();
146
147        let obj_futures = object_ids
148            .iter()
149            .map(|id| response::live_object(ctx, *id, &options));
150
151        Ok(future::join_all(obj_futures)
152            .await
153            .into_iter()
154            .zip_debug_eq(object_ids)
155            .map(|(r, o)| {
156                r.with_internal_context(|| format!("Failed to get object {o} at latest version"))
157            })
158            .collect::<Result<Vec<_>, _>>()?)
159    }
160
161    async fn try_get_past_object(
162        &self,
163        object_id: ObjectID,
164        version: SequenceNumber,
165        options: Option<SuiObjectDataOptions>,
166    ) -> RpcResult<SuiPastObjectResponse> {
167        let Self(ctx) = self;
168        let options = options.unwrap_or_default();
169        Ok(response::past_object(ctx, object_id, version, &options)
170            .await
171            .with_internal_context(|| {
172                format!(
173                    "Failed to get object {object_id} at version {}",
174                    version.value()
175                )
176            })?)
177    }
178
179    async fn try_multi_get_past_objects(
180        &self,
181        past_objects: Vec<SuiGetPastObjectRequest>,
182        options: Option<SuiObjectDataOptions>,
183    ) -> RpcResult<Vec<SuiPastObjectResponse>> {
184        let Self(ctx) = self;
185        let config = &ctx.config().objects;
186        if past_objects.len() > config.max_multi_get_objects {
187            return Err(invalid_params(Error::TooManyKeys {
188                requested: past_objects.len(),
189                max: config.max_multi_get_objects,
190            })
191            .into());
192        }
193
194        let options = options.unwrap_or_default();
195
196        let obj_futures = past_objects
197            .iter()
198            .map(|obj| response::past_object(ctx, obj.object_id, obj.version, &options));
199
200        Ok(future::join_all(obj_futures)
201            .await
202            .into_iter()
203            .zip_debug_eq(past_objects)
204            .map(|(r, o)| {
205                let id = o.object_id;
206                let v = o.version;
207                r.with_internal_context(|| format!("Failed to get object {id} at version {v}"))
208            })
209            .collect::<Result<Vec<_>, _>>()?)
210    }
211}
212
213#[async_trait::async_trait]
214impl QueryObjectsApiServer for QueryObjects {
215    async fn get_owned_objects(
216        &self,
217        address: SuiAddress,
218        query: Option<SuiObjectResponseQuery>,
219        cursor: Option<String>,
220        limit: Option<usize>,
221    ) -> RpcResult<Page<SuiObjectResponse, String>> {
222        let Self(ctx) = self;
223
224        let query = query.unwrap_or_default();
225
226        let Page {
227            data: object_ids,
228            next_cursor,
229            has_next_page,
230        } = filter::owned_objects(ctx, address, &query.filter, cursor, limit).await?;
231
232        let options = query.options.unwrap_or_default();
233
234        let obj_futures = object_ids
235            .iter()
236            .map(|id| response::live_object(ctx, *id, &options));
237
238        let data = future::join_all(obj_futures)
239            .await
240            .into_iter()
241            .zip_debug_eq(object_ids)
242            .map(|(r, id)| {
243                r.with_internal_context(|| format!("Failed to get object {id} at latest version"))
244            })
245            .collect::<Result<Vec<_>, _>>()?;
246
247        Ok(Page {
248            data,
249            next_cursor,
250            has_next_page,
251        })
252    }
253}
254
255impl RpcModule for Objects {
256    fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
257        self.into_rpc()
258    }
259}
260
261impl RpcModule for QueryObjects {
262    fn into_impl(self) -> jsonrpsee::RpcModule<Self> {
263        self.into_rpc()
264    }
265}