casper_types/transaction/
package_identifier.rs1use alloc::{string::String, vec::Vec};
2use core::fmt::{self, Display, Formatter};
3
4#[cfg(feature = "datasize")]
5use datasize::DataSize;
6use hex_fmt::HexFmt;
7#[cfg(any(feature = "testing", test))]
8use rand::Rng;
9#[cfg(feature = "json-schema")]
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13#[cfg(any(feature = "testing", test))]
14use crate::testing::TestRng;
15use crate::{
16 bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
17 contracts::ProtocolVersionMajor,
18 EntityVersion, PackageHash,
19};
20#[cfg(doc)]
21use crate::{ExecutableDeployItem, TransactionTarget};
22
23const HASH_TAG: u8 = 0;
24const NAME_TAG: u8 = 1;
25const HASH_WITH_VERSION_TAG: u8 = 2;
26const NAME_WITH_VERSION_TAG: u8 = 3;
27
28#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, Debug)]
31#[cfg_attr(feature = "datasize", derive(DataSize))]
32#[cfg_attr(
33 feature = "json-schema",
34 derive(JsonSchema),
35 schemars(
36 description = "Identifier for the package object within a `Stored` transaction target or \
37 an `ExecutableDeployItem`."
38 )
39)]
40pub enum PackageIdentifier {
41 Hash {
43 package_hash: PackageHash,
45 version: Option<EntityVersion>,
49 },
50 Name {
52 name: String,
54 version: Option<EntityVersion>,
58 },
59 HashWithMajorVersion {
61 package_hash: PackageHash,
63 protocol_version_major: Option<ProtocolVersionMajor>,
67 version: Option<EntityVersion>,
71 },
72 NameWithMajorVersion {
74 name: String,
76 protocol_version_major: Option<ProtocolVersionMajor>,
80 version: Option<EntityVersion>,
84 },
85}
86
87impl PackageIdentifier {
88 pub fn version(&self) -> Option<EntityVersion> {
92 match self {
93 PackageIdentifier::HashWithMajorVersion { version, .. }
94 | PackageIdentifier::NameWithMajorVersion { version, .. }
95 | PackageIdentifier::Hash { version, .. }
96 | PackageIdentifier::Name { version, .. } => *version,
97 }
98 }
99
100 pub fn protocol_version_major(&self) -> Option<ProtocolVersionMajor> {
104 match self {
105 PackageIdentifier::HashWithMajorVersion {
106 protocol_version_major,
107 ..
108 }
109 | PackageIdentifier::NameWithMajorVersion {
110 protocol_version_major,
111 ..
112 } => *protocol_version_major,
113 PackageIdentifier::Hash { .. } | PackageIdentifier::Name { .. } => None,
114 }
115 }
116
117 #[cfg(any(feature = "testing", test))]
119 pub fn random(rng: &mut TestRng) -> Self {
120 match rng.gen_range(0..4) {
121 0 => PackageIdentifier::Hash {
122 package_hash: PackageHash::new(rng.gen()),
123 version: rng.gen(),
124 },
125 1 => PackageIdentifier::Name {
126 name: rng.random_string(1..21),
127 version: rng.gen(),
128 },
129 2 => PackageIdentifier::HashWithMajorVersion {
130 package_hash: PackageHash::new(rng.gen()),
131 protocol_version_major: rng.gen(),
132 version: rng.gen(),
133 },
134 3 => PackageIdentifier::NameWithMajorVersion {
135 name: rng.random_string(1..21),
136 protocol_version_major: rng.gen(),
137 version: rng.gen(),
138 },
139 _ => unreachable!("Unexpected tag"),
140 }
141 }
142}
143
144impl Display for PackageIdentifier {
145 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
146 match self {
147 PackageIdentifier::Hash {
148 package_hash: contract_package_hash,
149 version: Some(ver),
150 } => write!(
151 formatter,
152 "package-id({}, version {})",
153 HexFmt(contract_package_hash),
154 ver
155 ),
156 PackageIdentifier::Hash {
157 package_hash: contract_package_hash,
158 ..
159 } => write!(
160 formatter,
161 "package-id({}, latest)",
162 HexFmt(contract_package_hash),
163 ),
164 PackageIdentifier::Name {
165 name,
166 version: Some(ver),
167 } => write!(formatter, "package-id({}, version {})", name, ver),
168 PackageIdentifier::Name { name, .. } => {
169 write!(formatter, "package-id({}, latest)", name)
170 }
171 PackageIdentifier::HashWithMajorVersion {
172 package_hash,
173 protocol_version_major,
174 version,
175 } => {
176 write!(
177 formatter,
178 "package-id-HashWithVersion({}, protocol_version_major: {:?}, version: {:?})",
179 HexFmt(package_hash),
180 protocol_version_major,
181 version,
182 )
183 }
184 PackageIdentifier::NameWithMajorVersion {
185 name,
186 protocol_version_major,
187 version,
188 } => {
189 write!(
190 formatter,
191 "package-id-NameWithVersion({},protocol_version_major: {:?}, version: {:?})",
192 name, protocol_version_major, version,
193 )
194 }
195 }
196 }
197}
198
199impl ToBytes for PackageIdentifier {
200 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
201 match self {
202 PackageIdentifier::Hash {
203 package_hash,
204 version,
205 } => {
206 HASH_TAG.write_bytes(writer)?;
207 package_hash.write_bytes(writer)?;
208 version.write_bytes(writer)
209 }
210 PackageIdentifier::Name { name, version } => {
211 NAME_TAG.write_bytes(writer)?;
212 name.write_bytes(writer)?;
213 version.write_bytes(writer)
214 }
215 PackageIdentifier::HashWithMajorVersion {
216 package_hash,
217 protocol_version_major,
218 version,
219 } => {
220 HASH_WITH_VERSION_TAG.write_bytes(writer)?;
221 package_hash.write_bytes(writer)?;
222 protocol_version_major.write_bytes(writer)?;
223 version.write_bytes(writer)
224 }
225 PackageIdentifier::NameWithMajorVersion {
226 name,
227 protocol_version_major,
228 version,
229 } => {
230 NAME_WITH_VERSION_TAG.write_bytes(writer)?;
231 name.write_bytes(writer)?;
232 protocol_version_major.write_bytes(writer)?;
233 version.write_bytes(writer)
234 }
235 }
236 }
237
238 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
239 let mut buffer = bytesrepr::allocate_buffer(self)?;
240 self.write_bytes(&mut buffer)?;
241 Ok(buffer)
242 }
243
244 fn serialized_length(&self) -> usize {
245 U8_SERIALIZED_LENGTH
246 + match self {
247 PackageIdentifier::Hash {
248 package_hash,
249 version,
250 } => package_hash.serialized_length() + version.serialized_length(),
251 PackageIdentifier::Name { name, version } => {
252 name.serialized_length() + version.serialized_length()
253 }
254 PackageIdentifier::HashWithMajorVersion {
255 package_hash,
256 protocol_version_major,
257 version,
258 } => {
259 package_hash.serialized_length()
260 + protocol_version_major.serialized_length()
261 + version.serialized_length()
262 }
263 PackageIdentifier::NameWithMajorVersion {
264 name,
265 protocol_version_major,
266 version,
267 } => {
268 name.serialized_length()
269 + protocol_version_major.serialized_length()
270 + version.serialized_length()
271 }
272 }
273 }
274}
275
276impl FromBytes for PackageIdentifier {
277 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
278 let (tag, remainder) = u8::from_bytes(bytes)?;
279 match tag {
280 HASH_TAG => {
281 let (package_hash, remainder) = PackageHash::from_bytes(remainder)?;
282 let (version, remainder) = Option::<EntityVersion>::from_bytes(remainder)?;
283 let id = PackageIdentifier::Hash {
284 package_hash,
285 version,
286 };
287 Ok((id, remainder))
288 }
289 NAME_TAG => {
290 let (name, remainder) = String::from_bytes(remainder)?;
291 let (version, remainder) = Option::<EntityVersion>::from_bytes(remainder)?;
292 let id = PackageIdentifier::Name { name, version };
293 Ok((id, remainder))
294 }
295 HASH_WITH_VERSION_TAG => {
296 let (package_hash, remainder) = PackageHash::from_bytes(remainder)?;
297 let (protocol_version_major, remainder) = Option::from_bytes(remainder)?;
298 let (version, remainder) = Option::from_bytes(remainder)?;
299 let id = PackageIdentifier::HashWithMajorVersion {
300 package_hash,
301 protocol_version_major,
302 version,
303 };
304 Ok((id, remainder))
305 }
306 NAME_WITH_VERSION_TAG => {
307 let (name, remainder) = String::from_bytes(remainder)?;
308 let (protocol_version_major, remainder) = Option::from_bytes(remainder)?;
309 let (version, remainder) = Option::from_bytes(remainder)?;
310 let id = PackageIdentifier::NameWithMajorVersion {
311 name,
312 protocol_version_major,
313 version,
314 };
315 Ok((id, remainder))
316 }
317 _ => Err(bytesrepr::Error::Formatting),
318 }
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn bytesrepr_roundtrip() {
328 let rng = &mut TestRng::new();
329 bytesrepr::test_serialization_roundtrip(&PackageIdentifier::random(rng));
330 }
331}