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