1use alloc::{
4 collections::{BTreeMap, BTreeSet},
5 format,
6 string::String,
7 vec::Vec,
8};
9use core::{
10 convert::TryFrom,
11 fmt::{self, Debug, Display, Formatter},
12};
13
14#[cfg(feature = "datasize")]
15use datasize::DataSize;
16#[cfg(feature = "json-schema")]
17use schemars::JsonSchema;
18use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
19#[cfg(feature = "json-schema")]
20use serde_map_to_array::KeyValueJsonSchema;
21use serde_map_to_array::{BTreeMapToArray, KeyValueLabels};
22
23use crate::{
24 addressable_entity::{Error, FromStrError},
25 bytesrepr::{self, FromBytes, ToBytes, U32_SERIALIZED_LENGTH},
26 checksummed_hex,
27 crypto::{self, PublicKey},
28 uref::URef,
29 CLType, CLTyped, EntityAddr, HashAddr, BLAKE2B_DIGEST_LENGTH, KEY_HASH_LENGTH,
30};
31
32const PACKAGE_STRING_PREFIX: &str = "package-";
33
34#[derive(Debug)]
36pub struct TryFromSliceForPackageHashError(());
37
38impl Display for TryFromSliceForPackageHashError {
39 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
40 write!(f, "failed to retrieve from slice")
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
47#[cfg_attr(feature = "datasize", derive(DataSize))]
48#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
49pub struct Group(String);
50
51impl Group {
52 pub fn new<T: Into<String>>(s: T) -> Self {
54 Group(s.into())
55 }
56
57 pub fn value(&self) -> &str {
59 &self.0
60 }
61}
62
63impl From<Group> for String {
64 fn from(group: Group) -> Self {
65 group.0
66 }
67}
68
69impl ToBytes for Group {
70 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
71 self.0.to_bytes()
72 }
73
74 fn serialized_length(&self) -> usize {
75 self.0.serialized_length()
76 }
77
78 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
79 self.value().write_bytes(writer)?;
80 Ok(())
81 }
82}
83
84impl FromBytes for Group {
85 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
86 String::from_bytes(bytes).map(|(label, bytes)| (Group(label), bytes))
87 }
88}
89
90pub type EntityVersion = u32;
92
93pub const ENTITY_INITIAL_VERSION: EntityVersion = 1;
95
96pub type ProtocolVersionMajor = u32;
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
101#[cfg_attr(feature = "datasize", derive(DataSize))]
102#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
103pub struct EntityVersionKey {
104 protocol_version_major: ProtocolVersionMajor,
106 entity_version: EntityVersion,
108}
109
110impl EntityVersionKey {
111 pub fn new(
113 protocol_version_major: ProtocolVersionMajor,
114 entity_version: EntityVersion,
115 ) -> Self {
116 Self {
117 protocol_version_major,
118 entity_version,
119 }
120 }
121
122 pub fn protocol_version_major(self) -> ProtocolVersionMajor {
124 self.protocol_version_major
125 }
126
127 pub fn entity_version(self) -> EntityVersion {
129 self.entity_version
130 }
131}
132
133impl From<EntityVersionKey> for (ProtocolVersionMajor, EntityVersion) {
134 fn from(entity_version_key: EntityVersionKey) -> Self {
135 (
136 entity_version_key.protocol_version_major,
137 entity_version_key.entity_version,
138 )
139 }
140}
141
142impl ToBytes for EntityVersionKey {
143 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
144 let mut buffer = bytesrepr::allocate_buffer(self)?;
145 self.write_bytes(&mut buffer)?;
146 Ok(buffer)
147 }
148
149 fn serialized_length(&self) -> usize {
150 ENTITY_VERSION_KEY_SERIALIZED_LENGTH
151 }
152
153 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
154 self.protocol_version_major.write_bytes(writer)?;
155 self.entity_version.write_bytes(writer)
156 }
157}
158
159impl FromBytes for EntityVersionKey {
160 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
161 let (protocol_version_major, remainder) = ProtocolVersionMajor::from_bytes(bytes)?;
162 let (entity_version, remainder) = EntityVersion::from_bytes(remainder)?;
163 Ok((
164 EntityVersionKey {
165 protocol_version_major,
166 entity_version,
167 },
168 remainder,
169 ))
170 }
171}
172
173impl Display for EntityVersionKey {
174 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
175 write!(f, "{}.{}", self.protocol_version_major, self.entity_version)
176 }
177}
178
179pub const ENTITY_VERSION_KEY_SERIALIZED_LENGTH: usize =
181 U32_SERIALIZED_LENGTH + U32_SERIALIZED_LENGTH;
182
183#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize, Debug)]
185#[cfg_attr(feature = "datasize", derive(DataSize))]
186#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
187#[serde(transparent, deny_unknown_fields)]
188pub struct EntityVersions(
189 #[serde(with = "BTreeMapToArray::<EntityVersionKey, EntityAddr, EntityVersionLabels>")]
190 BTreeMap<EntityVersionKey, EntityAddr>,
191);
192
193impl EntityVersions {
194 pub const fn new() -> Self {
196 EntityVersions(BTreeMap::new())
197 }
198
199 pub fn contract_hashes(&self) -> impl Iterator<Item = &EntityAddr> {
201 self.0.values()
202 }
203
204 pub fn get(&self, key: &EntityVersionKey) -> Option<&EntityAddr> {
206 self.0.get(key)
207 }
208
209 pub fn maybe_first(&mut self) -> Option<(EntityVersionKey, EntityAddr)> {
211 if let Some((entity_version_key, entity_hash)) = self.0.iter().next() {
212 Some((*entity_version_key, *entity_hash))
213 } else {
214 None
215 }
216 }
217
218 pub fn version_count(&self) -> usize {
220 self.0.len()
221 }
222
223 pub fn latest(&self) -> Option<&EntityAddr> {
225 let (_, value) = self.0.last_key_value()?;
226 Some(value)
227 }
228}
229
230impl ToBytes for EntityVersions {
231 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
232 self.0.to_bytes()
233 }
234
235 fn serialized_length(&self) -> usize {
236 self.0.serialized_length()
237 }
238
239 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
240 self.0.write_bytes(writer)
241 }
242}
243
244impl FromBytes for EntityVersions {
245 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
246 let (versions, remainder) = BTreeMap::<EntityVersionKey, EntityAddr>::from_bytes(bytes)?;
247 Ok((EntityVersions(versions), remainder))
248 }
249}
250
251impl From<BTreeMap<EntityVersionKey, EntityAddr>> for EntityVersions {
252 fn from(value: BTreeMap<EntityVersionKey, EntityAddr>) -> Self {
253 EntityVersions(value)
254 }
255}
256
257struct EntityVersionLabels;
258
259impl KeyValueLabels for EntityVersionLabels {
260 const KEY: &'static str = "entity_version_key";
261 const VALUE: &'static str = "entity_addr";
262}
263
264#[cfg(feature = "json-schema")]
265impl KeyValueJsonSchema for EntityVersionLabels {
266 const JSON_SCHEMA_KV_NAME: Option<&'static str> = Some("EntityVersionAndEntityAddr");
267}
268
269#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize, Debug)]
271#[cfg_attr(feature = "datasize", derive(DataSize))]
272#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
273#[serde(transparent, deny_unknown_fields)]
274pub struct Groups(
275 #[serde(with = "BTreeMapToArray::<Group, BTreeSet::<URef>, GroupLabels>")]
276 pub(crate) BTreeMap<Group, BTreeSet<URef>>,
277);
278
279impl Groups {
280 pub const fn new() -> Self {
282 Groups(BTreeMap::new())
283 }
284
285 pub fn insert(&mut self, name: Group, urefs: BTreeSet<URef>) -> Option<BTreeSet<URef>> {
290 self.0.insert(name, urefs)
291 }
292
293 pub fn contains(&self, name: &Group) -> bool {
295 self.0.contains_key(name)
296 }
297
298 pub fn get(&self, name: &Group) -> Option<&BTreeSet<URef>> {
300 self.0.get(name)
301 }
302
303 pub fn get_mut(&mut self, name: &Group) -> Option<&mut BTreeSet<URef>> {
305 self.0.get_mut(name)
306 }
307
308 pub fn len(&self) -> usize {
310 self.0.len()
311 }
312
313 pub fn is_empty(&self) -> bool {
315 self.0.is_empty()
316 }
317
318 pub fn keys(&self) -> impl Iterator<Item = &BTreeSet<URef>> {
320 self.0.values()
321 }
322
323 pub fn total_urefs(&self) -> usize {
325 self.0.values().map(|urefs| urefs.len()).sum()
326 }
327}
328
329impl ToBytes for Groups {
330 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
331 self.0.to_bytes()
332 }
333
334 fn serialized_length(&self) -> usize {
335 self.0.serialized_length()
336 }
337
338 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
339 self.0.write_bytes(writer)
340 }
341}
342
343impl FromBytes for Groups {
344 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
345 let (groups, remainder) = BTreeMap::<Group, BTreeSet<URef>>::from_bytes(bytes)?;
346 Ok((Groups(groups), remainder))
347 }
348}
349
350struct GroupLabels;
351
352impl KeyValueLabels for GroupLabels {
353 const KEY: &'static str = "group_name";
354 const VALUE: &'static str = "group_users";
355}
356
357#[cfg(feature = "json-schema")]
358impl KeyValueJsonSchema for GroupLabels {
359 const JSON_SCHEMA_KV_NAME: Option<&'static str> = Some("NamedUserGroup");
360}
361
362#[cfg(any(feature = "testing", feature = "gens", test))]
363impl From<BTreeMap<Group, BTreeSet<URef>>> for Groups {
364 fn from(value: BTreeMap<Group, BTreeSet<URef>>) -> Self {
365 Groups(value)
366 }
367}
368
369#[derive(Default, PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy)]
371#[cfg_attr(feature = "datasize", derive(DataSize))]
372#[cfg_attr(
373 feature = "json-schema",
374 derive(JsonSchema),
375 schemars(description = "The hex-encoded address of the Package.")
376)]
377pub struct PackageHash(
378 #[cfg_attr(feature = "json-schema", schemars(skip, with = "String"))] HashAddr,
379);
380
381impl PackageHash {
382 pub const fn new(value: HashAddr) -> PackageHash {
384 PackageHash(value)
385 }
386
387 pub fn value(&self) -> HashAddr {
389 self.0
390 }
391
392 pub fn as_bytes(&self) -> &[u8] {
394 &self.0
395 }
396
397 pub fn to_formatted_string(self) -> String {
399 format!("{}{}", PACKAGE_STRING_PREFIX, base16::encode_lower(&self.0),)
400 }
401
402 pub fn from_formatted_str(input: &str) -> Result<Self, FromStrError> {
405 let hex_addr = input
406 .strip_prefix(PACKAGE_STRING_PREFIX)
407 .ok_or(FromStrError::InvalidPrefix)?;
408
409 let bytes = HashAddr::try_from(checksummed_hex::decode(hex_addr)?.as_ref())?;
410 Ok(PackageHash(bytes))
411 }
412
413 pub fn from_public_key(
415 public_key: &PublicKey,
416 blake2b_hash_fn: impl Fn(Vec<u8>) -> [u8; BLAKE2B_DIGEST_LENGTH],
417 ) -> Self {
418 const SYSTEM_LOWERCASE: &str = "system";
419 const ED25519_LOWERCASE: &str = "ed25519";
420 const SECP256K1_LOWERCASE: &str = "secp256k1";
421
422 let algorithm_name = match public_key {
423 PublicKey::System => SYSTEM_LOWERCASE,
424 PublicKey::Ed25519(_) => ED25519_LOWERCASE,
425 PublicKey::Secp256k1(_) => SECP256K1_LOWERCASE,
426 };
427 let public_key_bytes: Vec<u8> = public_key.into();
428
429 let preimage = {
431 let mut data = Vec::with_capacity(algorithm_name.len() + public_key_bytes.len() + 1);
432 data.extend(algorithm_name.as_bytes());
433 data.push(0);
434 data.extend(public_key_bytes);
435 data
436 };
437 let digest = blake2b_hash_fn(preimage);
439 Self::new(digest)
440 }
441}
442
443impl Display for PackageHash {
444 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
445 write!(f, "{}", base16::encode_lower(&self.0))
446 }
447}
448
449impl Debug for PackageHash {
450 fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
451 write!(f, "PackageHash({})", base16::encode_lower(&self.0))
452 }
453}
454
455impl CLTyped for PackageHash {
456 fn cl_type() -> CLType {
457 CLType::ByteArray(KEY_HASH_LENGTH as u32)
458 }
459}
460
461impl ToBytes for PackageHash {
462 #[inline(always)]
463 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
464 self.0.to_bytes()
465 }
466
467 #[inline(always)]
468 fn serialized_length(&self) -> usize {
469 self.0.serialized_length()
470 }
471
472 #[inline(always)]
473 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
474 writer.extend_from_slice(&self.0);
475 Ok(())
476 }
477}
478
479impl FromBytes for PackageHash {
480 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
481 let (bytes, rem) = FromBytes::from_bytes(bytes)?;
482 Ok((PackageHash::new(bytes), rem))
483 }
484}
485
486impl From<[u8; 32]> for PackageHash {
487 fn from(bytes: [u8; 32]) -> Self {
488 PackageHash(bytes)
489 }
490}
491
492impl Serialize for PackageHash {
493 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
494 if serializer.is_human_readable() {
495 self.to_formatted_string().serialize(serializer)
496 } else {
497 self.0.serialize(serializer)
498 }
499 }
500}
501
502impl<'de> Deserialize<'de> for PackageHash {
503 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
504 if deserializer.is_human_readable() {
505 let formatted_string = String::deserialize(deserializer)?;
506 PackageHash::from_formatted_str(&formatted_string).map_err(SerdeError::custom)
507 } else {
508 let bytes = HashAddr::deserialize(deserializer)?;
509 Ok(PackageHash(bytes))
510 }
511 }
512}
513
514impl AsRef<[u8]> for PackageHash {
515 fn as_ref(&self) -> &[u8] {
516 self.0.as_ref()
517 }
518}
519
520impl TryFrom<&[u8]> for PackageHash {
521 type Error = TryFromSliceForPackageHashError;
522
523 fn try_from(bytes: &[u8]) -> Result<Self, TryFromSliceForPackageHashError> {
524 HashAddr::try_from(bytes)
525 .map(PackageHash::new)
526 .map_err(|_| TryFromSliceForPackageHashError(()))
527 }
528}
529
530impl TryFrom<&Vec<u8>> for PackageHash {
531 type Error = TryFromSliceForPackageHashError;
532
533 fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
534 HashAddr::try_from(bytes as &[u8])
535 .map(PackageHash::new)
536 .map_err(|_| TryFromSliceForPackageHashError(()))
537 }
538}
539
540impl From<&PublicKey> for PackageHash {
541 fn from(public_key: &PublicKey) -> Self {
542 PackageHash::from_public_key(public_key, crypto::blake2b)
543 }
544}
545
546#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
548#[cfg_attr(feature = "datasize", derive(DataSize))]
549#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
550pub enum PackageStatus {
551 Locked,
553 Unlocked,
555}
556
557impl PackageStatus {
558 pub fn new(is_locked: bool) -> Self {
560 if is_locked {
561 PackageStatus::Locked
562 } else {
563 PackageStatus::Unlocked
564 }
565 }
566}
567
568impl Default for PackageStatus {
569 fn default() -> Self {
570 Self::Unlocked
571 }
572}
573
574impl ToBytes for PackageStatus {
575 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
576 let mut result = bytesrepr::allocate_buffer(self)?;
577 match self {
578 PackageStatus::Unlocked => result.append(&mut false.to_bytes()?),
579 PackageStatus::Locked => result.append(&mut true.to_bytes()?),
580 }
581 Ok(result)
582 }
583
584 fn serialized_length(&self) -> usize {
585 match self {
586 PackageStatus::Unlocked => false.serialized_length(),
587 PackageStatus::Locked => true.serialized_length(),
588 }
589 }
590
591 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
592 match self {
593 PackageStatus::Locked => writer.push(u8::from(true)),
594 PackageStatus::Unlocked => writer.push(u8::from(false)),
595 }
596 Ok(())
597 }
598}
599
600impl FromBytes for PackageStatus {
601 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
602 let (val, bytes) = bool::from_bytes(bytes)?;
603 let status = PackageStatus::new(val);
604 Ok((status, bytes))
605 }
606}
607
608#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
610#[cfg_attr(feature = "datasize", derive(DataSize))]
611#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
612pub struct Package {
613 versions: EntityVersions,
615 disabled_versions: BTreeSet<EntityVersionKey>,
618 groups: Groups,
622 lock_status: PackageStatus,
624}
625
626impl CLTyped for Package {
627 fn cl_type() -> CLType {
628 CLType::Any
629 }
630}
631
632impl Package {
633 pub fn new(
635 versions: EntityVersions,
636 disabled_versions: BTreeSet<EntityVersionKey>,
637 groups: Groups,
638 lock_status: PackageStatus,
639 ) -> Self {
640 Package {
641 versions,
642 disabled_versions,
643 groups,
644 lock_status,
645 }
646 }
647
648 pub fn enable_version(&mut self, entity_addr: EntityAddr) -> Result<(), Error> {
650 let entity_version_key = self
651 .find_entity_version_key_by_hash(&entity_addr)
652 .copied()
653 .ok_or(Error::EntityNotFound)?;
654
655 self.disabled_versions.remove(&entity_version_key);
656
657 Ok(())
658 }
659
660 pub fn groups_mut(&mut self) -> &mut Groups {
662 &mut self.groups
663 }
664
665 pub fn groups(&self) -> &Groups {
667 &self.groups
668 }
669
670 pub fn add_group(&mut self, group: Group, urefs: BTreeSet<URef>) {
672 let v = self.groups.0.entry(group).or_default();
673 v.extend(urefs)
674 }
675
676 pub fn lookup_entity_hash(&self, entity_version_key: EntityVersionKey) -> Option<&EntityAddr> {
678 self.versions.0.get(&entity_version_key)
679 }
680
681 pub fn is_version_missing(&self, entity_version_key: EntityVersionKey) -> bool {
683 !self.versions.0.contains_key(&entity_version_key)
684 }
685
686 pub fn is_version_enabled(&self, entity_version_key: EntityVersionKey) -> bool {
688 !self.is_version_missing(entity_version_key)
689 && !self.disabled_versions.contains(&entity_version_key)
690 }
691
692 pub fn is_entity_enabled(&self, entity_hash: &EntityAddr) -> bool {
694 match self.find_entity_version_key_by_hash(entity_hash) {
695 Some(version_key) => !self.disabled_versions.contains(version_key),
696 None => false,
697 }
698 }
699
700 pub fn insert_entity_version(
702 &mut self,
703 protocol_version_major: ProtocolVersionMajor,
704 entity_hash: EntityAddr,
705 ) -> EntityVersionKey {
706 let contract_version = self.next_entity_version_for(protocol_version_major);
707 let key = EntityVersionKey::new(protocol_version_major, contract_version);
708 self.versions.0.insert(key, entity_hash);
709 key
710 }
711
712 pub fn disable_entity_version(&mut self, entity_hash: EntityAddr) -> Result<(), Error> {
714 let entity_version_key = self
715 .versions
716 .0
717 .iter()
718 .filter_map(|(k, v)| if *v == entity_hash { Some(*k) } else { None })
719 .next()
720 .ok_or(Error::EntityNotFound)?;
721
722 if !self.disabled_versions.contains(&entity_version_key) {
723 self.disabled_versions.insert(entity_version_key);
724 }
725
726 Ok(())
727 }
728
729 fn find_entity_version_key_by_hash(
730 &self,
731 entity_hash: &EntityAddr,
732 ) -> Option<&EntityVersionKey> {
733 self.versions
734 .0
735 .iter()
736 .filter_map(|(k, v)| if v == entity_hash { Some(k) } else { None })
737 .next()
738 }
739
740 pub fn versions(&self) -> &EntityVersions {
742 &self.versions
743 }
744
745 pub fn enabled_versions(&self) -> EntityVersions {
747 let mut ret = EntityVersions::new();
748 for version in &self.versions.0 {
749 if !self.is_version_enabled(*version.0) {
750 continue;
751 }
752 ret.0.insert(*version.0, *version.1);
753 }
754 ret
755 }
756
757 pub fn versions_mut(&mut self) -> &mut EntityVersions {
759 &mut self.versions
760 }
761
762 pub fn take_versions(self) -> EntityVersions {
764 self.versions
765 }
766
767 pub fn disabled_versions(&self) -> &BTreeSet<EntityVersionKey> {
769 &self.disabled_versions
770 }
771
772 pub fn disabled_versions_mut(&mut self) -> &mut BTreeSet<EntityVersionKey> {
774 &mut self.disabled_versions
775 }
776
777 pub fn remove_group(&mut self, group: &Group) -> bool {
779 self.groups.0.remove(group).is_some()
780 }
781
782 pub fn next_entity_version_for(&self, protocol_version: ProtocolVersionMajor) -> EntityVersion {
784 let current_version = self
785 .versions
786 .0
787 .keys()
788 .rev()
789 .find_map(|&entity_version_key| {
790 if entity_version_key.protocol_version_major() == protocol_version {
791 Some(entity_version_key.entity_version())
792 } else {
793 None
794 }
795 })
796 .unwrap_or(0);
797
798 current_version + 1
799 }
800
801 pub fn current_entity_version(&self) -> Option<EntityVersionKey> {
803 self.enabled_versions().0.keys().next_back().copied()
804 }
805
806 pub fn current_entity_hash(&self) -> Option<EntityAddr> {
808 self.enabled_versions().0.values().next_back().copied()
809 }
810
811 pub fn is_locked(&self) -> bool {
813 if self.versions.0.is_empty() {
814 return false;
815 }
816
817 match self.lock_status {
818 PackageStatus::Unlocked => false,
819 PackageStatus::Locked => true,
820 }
821 }
822
823 pub fn get_lock_status(&self) -> PackageStatus {
825 self.lock_status.clone()
826 }
827}
828
829impl ToBytes for Package {
830 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
831 let mut buffer = bytesrepr::allocate_buffer(self)?;
832 self.write_bytes(&mut buffer)?;
833 Ok(buffer)
834 }
835
836 fn serialized_length(&self) -> usize {
837 self.versions.serialized_length()
838 + self.disabled_versions.serialized_length()
839 + self.groups.serialized_length()
840 + self.lock_status.serialized_length()
841 }
842
843 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
844 self.versions().write_bytes(writer)?;
845 self.disabled_versions().write_bytes(writer)?;
846 self.groups().write_bytes(writer)?;
847 self.lock_status.write_bytes(writer)?;
848
849 Ok(())
850 }
851}
852
853impl FromBytes for Package {
854 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
855 let (versions, bytes) = EntityVersions::from_bytes(bytes)?;
856 let (disabled_versions, bytes) = BTreeSet::<EntityVersionKey>::from_bytes(bytes)?;
857 let (groups, bytes) = Groups::from_bytes(bytes)?;
858 let (lock_status, bytes) = PackageStatus::from_bytes(bytes)?;
859
860 let result = Package {
861 versions,
862 disabled_versions,
863 groups,
864 lock_status,
865 };
866
867 Ok((result, bytes))
868 }
869}
870
871#[cfg(test)]
872mod tests {
873 use core::iter::FromIterator;
874
875 use super::*;
876 use crate::{
877 AccessRights, EntityEntryPoint, EntityVersionKey, EntryPointAccess, EntryPointPayment,
878 EntryPointType, Parameter, ProtocolVersion, URef,
879 };
880 use alloc::borrow::ToOwned;
881
882 const ENTITY_HASH_V1: EntityAddr = EntityAddr::new_smart_contract([42; 32]);
883 const ENTITY_HASH_V2: EntityAddr = EntityAddr::new_smart_contract([84; 32]);
884
885 fn make_package_with_two_versions() -> Package {
886 let mut package = Package::new(
887 EntityVersions::default(),
888 BTreeSet::new(),
889 Groups::default(),
890 PackageStatus::default(),
891 );
892
893 {
895 let group_urefs = {
896 let mut ret = BTreeSet::new();
897 ret.insert(URef::new([1; 32], AccessRights::READ));
898 ret
899 };
900
901 package
902 .groups_mut()
903 .insert(Group::new("Group 1"), group_urefs.clone());
904
905 package
906 .groups_mut()
907 .insert(Group::new("Group 2"), group_urefs);
908 }
909
910 let _entry_points = {
912 let mut ret = BTreeMap::new();
913 let entrypoint = EntityEntryPoint::new(
914 "method0".to_string(),
915 vec![],
916 CLType::U32,
917 EntryPointAccess::groups(&["Group 2"]),
918 EntryPointType::Caller,
919 EntryPointPayment::Caller,
920 );
921 ret.insert(entrypoint.name().to_owned(), entrypoint);
922 let entrypoint = EntityEntryPoint::new(
923 "method1".to_string(),
924 vec![Parameter::new("Foo", CLType::U32)],
925 CLType::U32,
926 EntryPointAccess::groups(&["Group 1"]),
927 EntryPointType::Caller,
928 EntryPointPayment::Caller,
929 );
930 ret.insert(entrypoint.name().to_owned(), entrypoint);
931 ret
932 };
933
934 let protocol_version = ProtocolVersion::V1_0_0;
935
936 let v1 = package.insert_entity_version(protocol_version.value().major, ENTITY_HASH_V1);
937 let v2 = package.insert_entity_version(protocol_version.value().major, ENTITY_HASH_V2);
938 assert!(v2 > v1);
939
940 package
941 }
942
943 #[test]
944 fn next_entity_version() {
945 let major = 1;
946 let mut package = Package::new(
947 EntityVersions::default(),
948 BTreeSet::default(),
949 Groups::default(),
950 PackageStatus::default(),
951 );
952 assert_eq!(package.next_entity_version_for(major), 1);
953
954 let next_version =
955 package.insert_entity_version(major, EntityAddr::SmartContract([123; 32]));
956 assert_eq!(next_version, EntityVersionKey::new(major, 1));
957 assert_eq!(package.next_entity_version_for(major), 2);
958 let next_version_2 =
959 package.insert_entity_version(major, EntityAddr::SmartContract([124; 32]));
960 assert_eq!(next_version_2, EntityVersionKey::new(major, 2));
961
962 let major = 2;
963 assert_eq!(package.next_entity_version_for(major), 1);
964 let next_version_3 =
965 package.insert_entity_version(major, EntityAddr::SmartContract([42; 32]));
966 assert_eq!(next_version_3, EntityVersionKey::new(major, 1));
967 }
968
969 #[test]
970 fn roundtrip_serialization() {
971 let package = make_package_with_two_versions();
972 let bytes = package.to_bytes().expect("should serialize");
973 let (decoded_package, rem) = Package::from_bytes(&bytes).expect("should deserialize");
974 assert_eq!(package, decoded_package);
975 assert_eq!(rem.len(), 0);
976 }
977
978 #[test]
979 fn should_remove_group() {
980 let mut package = make_package_with_two_versions();
981
982 assert!(!package.remove_group(&Group::new("Non-existent group")));
983 assert!(package.remove_group(&Group::new("Group 1")));
984 assert!(!package.remove_group(&Group::new("Group 1"))); }
986
987 #[test]
988 fn should_disable_and_enable_entity_version() {
989 const ENTITY_HASH: EntityAddr = EntityAddr::new_smart_contract([123; 32]);
990
991 let mut package = make_package_with_two_versions();
992
993 assert!(
994 !package.is_entity_enabled(&ENTITY_HASH),
995 "nonexisting entity should return false"
996 );
997
998 assert_eq!(
999 package.current_entity_version(),
1000 Some(EntityVersionKey::new(1, 2))
1001 );
1002 assert_eq!(package.current_entity_hash(), Some(ENTITY_HASH_V2));
1003
1004 assert_eq!(
1005 package.versions(),
1006 &EntityVersions::from(BTreeMap::from_iter([
1007 (EntityVersionKey::new(1, 1), ENTITY_HASH_V1),
1008 (EntityVersionKey::new(1, 2), ENTITY_HASH_V2)
1009 ])),
1010 );
1011 assert_eq!(
1012 package.enabled_versions(),
1013 EntityVersions::from(BTreeMap::from_iter([
1014 (EntityVersionKey::new(1, 1), ENTITY_HASH_V1),
1015 (EntityVersionKey::new(1, 2), ENTITY_HASH_V2)
1016 ])),
1017 );
1018
1019 assert!(!package.is_entity_enabled(&ENTITY_HASH));
1020
1021 assert_eq!(
1022 package.disable_entity_version(ENTITY_HASH),
1023 Err(Error::EntityNotFound),
1024 "should return entity not found error"
1025 );
1026
1027 assert!(
1028 !package.is_entity_enabled(&ENTITY_HASH),
1029 "disabling missing entity shouldnt change outcome"
1030 );
1031
1032 let next_version = package.insert_entity_version(1, ENTITY_HASH);
1033 assert!(
1034 package.is_version_enabled(next_version),
1035 "version should exist and be enabled"
1036 );
1037 assert!(package.is_entity_enabled(&ENTITY_HASH));
1038
1039 assert!(
1040 package.is_entity_enabled(&ENTITY_HASH),
1041 "entity should be enabled"
1042 );
1043
1044 assert_eq!(
1045 package.disable_entity_version(ENTITY_HASH),
1046 Ok(()),
1047 "should be able to disable version"
1048 );
1049 assert!(!package.is_entity_enabled(&ENTITY_HASH));
1050
1051 assert!(
1052 !package.is_entity_enabled(&ENTITY_HASH),
1053 "entity should be disabled"
1054 );
1055 assert!(
1062 !package.is_version_enabled(next_version),
1063 "version should not be enabled"
1064 );
1065
1066 assert_eq!(
1067 package.current_entity_version(),
1068 Some(EntityVersionKey::new(1, 2))
1069 );
1070 assert_eq!(package.current_entity_hash(), Some(ENTITY_HASH_V2));
1071 assert_eq!(
1072 package.versions(),
1073 &EntityVersions::from(BTreeMap::from_iter([
1074 (EntityVersionKey::new(1, 1), ENTITY_HASH_V1),
1075 (EntityVersionKey::new(1, 2), ENTITY_HASH_V2),
1076 (next_version, ENTITY_HASH),
1077 ])),
1078 );
1079 assert_eq!(
1080 package.enabled_versions(),
1081 EntityVersions::from(BTreeMap::from_iter([
1082 (EntityVersionKey::new(1, 1), ENTITY_HASH_V1),
1083 (EntityVersionKey::new(1, 2), ENTITY_HASH_V2),
1084 ])),
1085 );
1086 assert_eq!(
1087 package.disabled_versions(),
1088 &BTreeSet::from_iter([next_version]),
1089 );
1090
1091 assert_eq!(
1092 package.current_entity_version(),
1093 Some(EntityVersionKey::new(1, 2))
1094 );
1095 assert_eq!(package.current_entity_hash(), Some(ENTITY_HASH_V2));
1096
1097 assert_eq!(
1098 package.disable_entity_version(ENTITY_HASH_V2),
1099 Ok(()),
1100 "should be able to disable version 2"
1101 );
1102
1103 assert_eq!(
1104 package.enabled_versions(),
1105 EntityVersions::from(BTreeMap::from_iter([(
1106 EntityVersionKey::new(1, 1),
1107 ENTITY_HASH_V1
1108 ),])),
1109 );
1110
1111 assert_eq!(
1112 package.current_entity_version(),
1113 Some(EntityVersionKey::new(1, 1))
1114 );
1115 assert_eq!(package.current_entity_hash(), Some(ENTITY_HASH_V1));
1116
1117 assert_eq!(
1118 package.disabled_versions(),
1119 &BTreeSet::from_iter([next_version, EntityVersionKey::new(1, 2)]),
1120 );
1121
1122 assert_eq!(package.enable_version(ENTITY_HASH_V2), Ok(()),);
1123
1124 assert_eq!(
1125 package.enabled_versions(),
1126 EntityVersions::from(BTreeMap::from_iter([
1127 (EntityVersionKey::new(1, 1), ENTITY_HASH_V1),
1128 (EntityVersionKey::new(1, 2), ENTITY_HASH_V2),
1129 ])),
1130 );
1131
1132 assert_eq!(
1133 package.disabled_versions(),
1134 &BTreeSet::from_iter([next_version])
1135 );
1136
1137 assert_eq!(package.current_entity_hash(), Some(ENTITY_HASH_V2));
1138
1139 assert_eq!(package.enable_version(ENTITY_HASH), Ok(()),);
1140
1141 assert_eq!(
1142 package.enable_version(ENTITY_HASH),
1143 Ok(()),
1144 "enabling a entity twice should be a noop"
1145 );
1146
1147 assert_eq!(
1148 package.enabled_versions(),
1149 EntityVersions::from(BTreeMap::from_iter([
1150 (EntityVersionKey::new(1, 1), ENTITY_HASH_V1),
1151 (EntityVersionKey::new(1, 2), ENTITY_HASH_V2),
1152 (next_version, ENTITY_HASH),
1153 ])),
1154 );
1155
1156 assert_eq!(package.disabled_versions(), &BTreeSet::new(),);
1157
1158 assert_eq!(package.current_entity_hash(), Some(ENTITY_HASH));
1159 }
1160
1161 #[test]
1162 fn should_not_allow_to_enable_non_existing_version() {
1163 let mut package = make_package_with_two_versions();
1164
1165 assert_eq!(
1166 package.enable_version(EntityAddr::SmartContract(HashAddr::default())),
1167 Err(Error::EntityNotFound),
1168 );
1169 }
1170
1171 #[test]
1172 fn package_hash_from_slice() {
1173 let bytes: Vec<u8> = (0..32).collect();
1174 let package_hash = HashAddr::try_from(&bytes[..]).expect("should create package hash");
1175 let package_hash = PackageHash::new(package_hash);
1176 assert_eq!(&bytes, &package_hash.as_bytes());
1177 }
1178
1179 #[test]
1180 fn package_hash_from_str() {
1181 let package_hash = PackageHash::new([3; 32]);
1182 let encoded = package_hash.to_formatted_string();
1183 let decoded = PackageHash::from_formatted_str(&encoded).unwrap();
1184 assert_eq!(package_hash, decoded);
1185
1186 let invalid_prefix =
1187 "package0000000000000000000000000000000000000000000000000000000000000000";
1188 assert!(matches!(
1189 PackageHash::from_formatted_str(invalid_prefix).unwrap_err(),
1190 FromStrError::InvalidPrefix
1191 ));
1192
1193 let short_addr = "package-00000000000000000000000000000000000000000000000000000000000000";
1194 assert!(matches!(
1195 PackageHash::from_formatted_str(short_addr).unwrap_err(),
1196 FromStrError::Hash(_)
1197 ));
1198
1199 let long_addr =
1200 "package-000000000000000000000000000000000000000000000000000000000000000000";
1201 assert!(matches!(
1202 PackageHash::from_formatted_str(long_addr).unwrap_err(),
1203 FromStrError::Hash(_)
1204 ));
1205
1206 let invalid_hex =
1207 "package-000000000000000000000000000000000000000000000000000000000000000g";
1208 assert!(matches!(
1209 PackageHash::from_formatted_str(invalid_hex).unwrap_err(),
1210 FromStrError::Hex(_)
1211 ));
1212 }
1213}
1214
1215#[cfg(test)]
1216mod prop_tests {
1217 use proptest::prelude::*;
1218
1219 use crate::{bytesrepr, gens};
1220
1221 proptest! {
1222 #[test]
1223 fn test_value_contract_package(contract_pkg in gens::package_arb()) {
1224 bytesrepr::test_serialization_roundtrip(&contract_pkg);
1225 }
1226 }
1227}