casper_types/
package.rs

1//! Module containing the Package and associated types for addressable entities.
2
3use 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/// Associated error type of `TryFrom<&[u8]>` for `ContractHash`.
35#[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/// A (labelled) "user group". Each method of a versioned contract may be
45/// associated with one or more user groups which are allowed to call it.
46#[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    /// Basic constructor
53    pub fn new<T: Into<String>>(s: T) -> Self {
54        Group(s.into())
55    }
56
57    /// Retrieves underlying name.
58    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
90/// Automatically incremented value for a contract version within a major `ProtocolVersion`.
91pub type EntityVersion = u32;
92
93/// Within each discrete major `ProtocolVersion`, entity version resets to this value.
94pub const ENTITY_INITIAL_VERSION: EntityVersion = 1;
95
96/// Major element of `ProtocolVersion` a `EntityVersion` is compatible with.
97pub type ProtocolVersionMajor = u32;
98
99/// Major element of `ProtocolVersion` combined with `EntityVersion`.
100#[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    /// Major element of `ProtocolVersion` a `ContractVersion` is compatible with.
105    protocol_version_major: ProtocolVersionMajor,
106    /// Automatically incremented value for a contract version within a major `ProtocolVersion`.
107    entity_version: EntityVersion,
108}
109
110impl EntityVersionKey {
111    /// Returns a new instance of ContractVersionKey with provided values.
112    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    /// Returns the major element of the protocol version this contract is compatible with.
123    pub fn protocol_version_major(self) -> ProtocolVersionMajor {
124        self.protocol_version_major
125    }
126
127    /// Returns the contract version within the protocol major version.
128    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
179/// Serialized length of `EntityVersionKey`.
180pub const ENTITY_VERSION_KEY_SERIALIZED_LENGTH: usize =
181    U32_SERIALIZED_LENGTH + U32_SERIALIZED_LENGTH;
182
183/// Collection of entity versions.
184#[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    /// Constructs a new, empty `EntityVersions`.
195    pub const fn new() -> Self {
196        EntityVersions(BTreeMap::new())
197    }
198
199    /// Returns an iterator over the `AddressableEntityHash`s (i.e. the map's values).
200    pub fn contract_hashes(&self) -> impl Iterator<Item = &EntityAddr> {
201        self.0.values()
202    }
203
204    /// Returns the `AddressableEntityHash` under the key
205    pub fn get(&self, key: &EntityVersionKey) -> Option<&EntityAddr> {
206        self.0.get(key)
207    }
208
209    /// Retrieve the first entity version key if it exists
210    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    /// The number of versions present in the package.
219    pub fn version_count(&self) -> usize {
220        self.0.len()
221    }
222
223    /// Returns the latest entity version key if it exists.
224    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/// Collection of named groups.
270#[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    /// Constructs a new, empty `Groups`.
281    pub const fn new() -> Self {
282        Groups(BTreeMap::new())
283    }
284
285    /// Inserts a named group.
286    ///
287    /// If the map did not have this name present, `None` is returned.  If the map did have this
288    /// name present, its collection of `URef`s is overwritten, and the collection is returned.
289    pub fn insert(&mut self, name: Group, urefs: BTreeSet<URef>) -> Option<BTreeSet<URef>> {
290        self.0.insert(name, urefs)
291    }
292
293    /// Returns `true` if the named group exists in the collection.
294    pub fn contains(&self, name: &Group) -> bool {
295        self.0.contains_key(name)
296    }
297
298    /// Returns a reference to the collection of `URef`s under the given `name` if any.
299    pub fn get(&self, name: &Group) -> Option<&BTreeSet<URef>> {
300        self.0.get(name)
301    }
302
303    /// Returns a mutable reference to the collection of `URef`s under the given `name` if any.
304    pub fn get_mut(&mut self, name: &Group) -> Option<&mut BTreeSet<URef>> {
305        self.0.get_mut(name)
306    }
307
308    /// Returns the number of named groups.
309    pub fn len(&self) -> usize {
310        self.0.len()
311    }
312
313    /// Returns `true` if there are no named groups.
314    pub fn is_empty(&self) -> bool {
315        self.0.is_empty()
316    }
317
318    /// Returns an iterator over the `Key`s (i.e. the map's values).
319    pub fn keys(&self) -> impl Iterator<Item = &BTreeSet<URef>> {
320        self.0.values()
321    }
322
323    /// Returns the total number of `URef`s contained in all the groups.
324    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/// A newtype wrapping a `HashAddr` which references a [`Package`] in the global state.
370#[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    /// Constructs a new `PackageHash` from the raw bytes of the package hash.
383    pub const fn new(value: HashAddr) -> PackageHash {
384        PackageHash(value)
385    }
386
387    /// Returns the raw bytes of the entity hash as an array.
388    pub fn value(&self) -> HashAddr {
389        self.0
390    }
391
392    /// Returns the raw bytes of the entity hash as a `slice`.
393    pub fn as_bytes(&self) -> &[u8] {
394        &self.0
395    }
396
397    /// Formats the `PackageHash` for users getting and putting.
398    pub fn to_formatted_string(self) -> String {
399        format!("{}{}", PACKAGE_STRING_PREFIX, base16::encode_lower(&self.0),)
400    }
401
402    /// Parses a string formatted as per `Self::to_formatted_string()` into a
403    /// `PackageHash`.
404    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    /// Parses a `PublicKey` and outputs the corresponding account hash.
414    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        // Prepare preimage based on the public key parameters.
430        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        // Hash the preimage data using blake2b256 and return it.
438        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/// A enum to determine the lock status of the package.
547#[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    /// The package is locked and cannot be versioned.
552    Locked,
553    /// The package is unlocked and can be versioned.
554    Unlocked,
555}
556
557impl PackageStatus {
558    /// Create a new status flag based on a boolean value
559    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/// Entity definition, metadata, and security container.
609#[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    /// All versions (enabled & disabled).
614    versions: EntityVersions,
615    /// Collection of disabled entity versions. The runtime will not permit disabled entity
616    /// versions to be executed.
617    disabled_versions: BTreeSet<EntityVersionKey>,
618    /// Mapping maintaining the set of URefs associated with each "user group". This can be used to
619    /// control access to methods in a particular version of the entity. A method is callable by
620    /// any context which "knows" any of the URefs associated with the method's user group.
621    groups: Groups,
622    /// A flag that determines whether a entity is locked
623    lock_status: PackageStatus,
624}
625
626impl CLTyped for Package {
627    fn cl_type() -> CLType {
628        CLType::Any
629    }
630}
631
632impl Package {
633    /// Create new `Package` (with no versions) from given access key.
634    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    /// Enable the entity version corresponding to the given hash (if it exists).
649    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    /// Get the mutable group definitions for this entity.
661    pub fn groups_mut(&mut self) -> &mut Groups {
662        &mut self.groups
663    }
664
665    /// Get the group definitions for this entity.
666    pub fn groups(&self) -> &Groups {
667        &self.groups
668    }
669
670    /// Adds new group to this entity.
671    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    /// Lookup the entity hash for a given entity version (if present)
677    pub fn lookup_entity_hash(&self, entity_version_key: EntityVersionKey) -> Option<&EntityAddr> {
678        self.versions.0.get(&entity_version_key)
679    }
680
681    /// Checks if the given entity version exists.
682    pub fn is_version_missing(&self, entity_version_key: EntityVersionKey) -> bool {
683        !self.versions.0.contains_key(&entity_version_key)
684    }
685
686    /// Checks if the given entity version exists and is available for use.
687    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    /// Returns `true` if the given entity hash exists and is enabled.
693    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    /// Insert a new entity version; the next sequential version number will be issued.
701    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    /// Disable the entity version corresponding to the given hash (if it exists).
713    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    /// Returns reference to all of this entity's versions.
741    pub fn versions(&self) -> &EntityVersions {
742        &self.versions
743    }
744
745    /// Returns all of this entity's enabled entity versions.
746    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    /// Returns mutable reference to all of this entity's versions (enabled and disabled).
758    pub fn versions_mut(&mut self) -> &mut EntityVersions {
759        &mut self.versions
760    }
761
762    /// Consumes the object and returns all of this entity's versions (enabled and disabled).
763    pub fn take_versions(self) -> EntityVersions {
764        self.versions
765    }
766
767    /// Returns all of this entity's disabled versions.
768    pub fn disabled_versions(&self) -> &BTreeSet<EntityVersionKey> {
769        &self.disabled_versions
770    }
771
772    /// Returns mut reference to all of this entity's disabled versions.
773    pub fn disabled_versions_mut(&mut self) -> &mut BTreeSet<EntityVersionKey> {
774        &mut self.disabled_versions
775    }
776
777    /// Removes a group from this entity (if it exists).
778    pub fn remove_group(&mut self, group: &Group) -> bool {
779        self.groups.0.remove(group).is_some()
780    }
781
782    /// Gets the next available entity version for the given protocol version
783    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    /// Return the entity version key for the newest enabled entity version.
802    pub fn current_entity_version(&self) -> Option<EntityVersionKey> {
803        self.enabled_versions().0.keys().next_back().copied()
804    }
805
806    /// Return the entity hash for the newest enabled entity version.
807    pub fn current_entity_hash(&self) -> Option<EntityAddr> {
808        self.enabled_versions().0.values().next_back().copied()
809    }
810
811    /// Return the lock status of the entity package.
812    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    /// Return the package status itself
824    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        // add groups
894        {
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        // add entry_points
911        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"))); // Group no longer exists
985    }
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        // This was once true, but look up vs disable checking have been decoupled in 2.0
1056        // assert_eq!(
1057        //     package.lookup_entity_hash(next_version),
1058        //     None,
1059        //     "should not return disabled entity version"
1060        // );
1061        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}