sui_rpc_api/grpc/v2/move_package_service/
get_package.rs1use crate::{
5 ErrorReason, Result, RpcError, RpcService,
6 grpc::v2::move_package_service::{
7 conversions::{convert_error, convert_module},
8 load_package, load_package_by_id,
9 },
10};
11use sui_rpc::proto::google::rpc::bad_request::FieldViolation;
12use sui_rpc::proto::sui::rpc::v2::get_package_request::Selector;
13use sui_rpc::proto::sui::rpc::v2::{GetPackageRequest, GetPackageResponse, Package};
14use sui_types::move_package::MovePackage;
15
16#[tracing::instrument(skip(service))]
17pub fn get_package(service: &RpcService, request: GetPackageRequest) -> Result<GetPackageResponse> {
18 let package_id_str = request.package_id.as_ref().ok_or_else(|| {
19 FieldViolation::new("package_id")
20 .with_description("missing package_id")
21 .with_reason(ErrorReason::FieldMissing)
22 })?;
23
24 let package = match request.selector {
25 Some(Selector::Version(version)) => {
26 load_package_at_version(service, package_id_str, version)?
27 }
28 Some(Selector::AtCheckpoint(at_checkpoint)) => {
29 load_package_at_checkpoint(service, package_id_str, at_checkpoint)?
30 }
31 None => load_package(service, package_id_str)?,
32 _ => {
33 return Err(FieldViolation::new("selector")
34 .with_description("unknown selector variant")
35 .with_reason(ErrorReason::FieldInvalid)
36 .into());
37 }
38 };
39
40 get_package_response(&package)
41}
42
43fn load_package_at_version(
49 service: &RpcService,
50 package_id_str: &str,
51 version: u64,
52) -> Result<MovePackage> {
53 let package = load_package(service, package_id_str)?;
54 let original_id = package.original_package_id();
55 if package.version().value() == version {
56 return Ok(package);
57 }
58
59 let indexes = service
60 .reader
61 .inner()
62 .indexes()
63 .ok_or_else(|| RpcError::new(tonic::Code::Unavailable, "rpc indexes are disabled"))?;
64
65 let storage_id = indexes
66 .get_package_version_storage_id(original_id, version)
67 .map_err(|e| RpcError::new(tonic::Code::Internal, e.to_string()))?
68 .ok_or_else(RpcError::not_found)?;
69
70 load_package_by_id(service, storage_id)
71}
72
73fn load_package_at_checkpoint(
81 service: &RpcService,
82 package_id_str: &str,
83 at_checkpoint: u64,
84) -> Result<MovePackage> {
85 let original_id = load_package(service, package_id_str)?.original_package_id();
86
87 let indexes = service
88 .reader
89 .inner()
90 .indexes()
91 .ok_or_else(|| RpcError::new(tonic::Code::Unavailable, "rpc indexes are disabled"))?;
92
93 let lowest_available = service.reader.get_lowest_available_checkpoint()?;
94 if at_checkpoint < lowest_available {
95 return Err(RpcError::new(
96 tonic::Code::NotFound,
97 format!(
98 "requested checkpoint {at_checkpoint} has been pruned; lowest available \
99 checkpoint is {lowest_available}",
100 ),
101 ));
102 }
103
104 let highest_indexed = indexes
105 .get_highest_indexed_checkpoint_seq_number()
106 .map_err(|e| RpcError::new(tonic::Code::Internal, e.to_string()))?
107 .ok_or_else(|| RpcError::new(tonic::Code::Unavailable, "rpc index is empty"))?;
108 if at_checkpoint > highest_indexed {
109 return Err(RpcError::new(
110 tonic::Code::NotFound,
111 format!(
112 "requested checkpoint {at_checkpoint} is not yet indexed; highest indexed \
113 checkpoint is {highest_indexed}",
114 ),
115 ));
116 }
117
118 let (_, storage_id) = indexes
119 .get_package_at_checkpoint(original_id, at_checkpoint)
120 .map_err(|e| RpcError::new(tonic::Code::Internal, e.to_string()))?
121 .ok_or_else(RpcError::not_found)?;
122
123 load_package_by_id(service, storage_id)
124}
125
126pub fn get_package_response(package: &MovePackage) -> Result<GetPackageResponse> {
129 let package_id = package.id();
130
131 let resolved_package =
132 sui_package_resolver::Package::read_from_package(package).map_err(convert_error)?;
133
134 let modules: Vec<_> = resolved_package
135 .modules()
136 .iter()
137 .map(|(module_name, resolver_module)| {
138 convert_module(module_name, resolver_module, &package_id)
139 })
140 .collect::<Result<Vec<_>>>()?;
141
142 let mut message = Package::default();
143 message.storage_id = Some(package_id.to_canonical_string(true));
144 message.original_id = Some(package.original_package_id().to_canonical_string(true));
145 message.version = Some(package.version().value());
146 message.modules = modules;
147
148 Ok(GetPackageResponse::new(message))
149}