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(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/// Associated error type of `TryFrom<&[u8]>` for `ContractHash`.
38#[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/// A (labelled) "user group". Each method of a versioned contract may be
48/// associated with one or more user groups which are allowed to call it.
49#[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    /// Basic constructor
56    pub fn new<T: Into<String>>(s: T) -> Self {
57        Group(s.into())
58    }
59
60    /// Retrieves underlying name.
61    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
93/// Automatically incremented value for a contract version within a major `ProtocolVersion`.
94pub type EntityVersion = u32;
95
96/// Within each discrete major `ProtocolVersion`, entity version resets to this value.
97pub const ENTITY_INITIAL_VERSION: EntityVersion = 1;
98
99/// Major element of `ProtocolVersion` a `EntityVersion` is compatible with.
100pub type ProtocolVersionMajor = u32;
101
102/// Major element of `ProtocolVersion` combined with `EntityVersion`.
103#[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    /// Major element of `ProtocolVersion` a `ContractVersion` is compatible with.
108    protocol_version_major: ProtocolVersionMajor,
109    /// Automatically incremented value for a contract version within a major `ProtocolVersion`.
110    entity_version: EntityVersion,
111}
112
113impl EntityVersionKey {
114    /// Returns a new instance of ContractVersionKey with provided values.
115    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    /// Returns the major element of the protocol version this contract is compatible with.
126    pub fn protocol_version_major(self) -> ProtocolVersionMajor {
127        self.protocol_version_major
128    }
129
130    /// Returns the contract version within the protocol major version.
131    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
192/// Serialized length of `EntityVersionKey`.
193pub const ENTITY_VERSION_KEY_SERIALIZED_LENGTH: usize =
194    U32_SERIALIZED_LENGTH + U32_SERIALIZED_LENGTH;
195
196/// Collection of entity versions.
197#[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    /// Constructs a new, empty `EntityVersions`.
208    pub const fn new() -> Self {
209        EntityVersions(BTreeMap::new())
210    }
211
212    /// Returns an iterator over the `AddressableEntityHash`s (i.e. the map's values).
213    pub fn contract_hashes(&self) -> impl Iterator<Item = &EntityAddr> {
214        self.0.values()
215    }
216
217    /// Returns the `AddressableEntityHash` under the key
218    pub fn get(&self, key: &EntityVersionKey) -> Option<&EntityAddr> {
219        self.0.get(key)
220    }
221
222    /// Retrieve the first entity version key if it exists
223    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    /// The number of versions present in the package.
232    pub fn version_count(&self) -> usize {
233        self.0.len()
234    }
235
236    /// Returns the latest entity version key if it exists.
237    pub fn latest(&self) -> Option<&EntityAddr> {
238        let (_, value) = self.0.last_key_value()?;
239        Some(value)
240    }
241
242    /// Returns an iterator over the `AddressableEntityHash`s (i.e. the map's values).
243    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/// Collection of named groups.
288#[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    /// Constructs a new, empty `Groups`.
299    pub const fn new() -> Self {
300        Groups(BTreeMap::new())
301    }
302
303    /// Inserts a named group.
304    ///
305    /// If the map did not have this name present, `None` is returned.  If the map did have this
306    /// name present, its collection of `URef`s is overwritten, and the collection is returned.
307    pub fn insert(&mut self, name: Group, urefs: BTreeSet<URef>) -> Option<BTreeSet<URef>> {
308        self.0.insert(name, urefs)
309    }
310
311    /// Returns `true` if the named group exists in the collection.
312    pub fn contains(&self, name: &Group) -> bool {
313        self.0.contains_key(name)
314    }
315
316    /// Returns a reference to the collection of `URef`s under the given `name` if any.
317    pub fn get(&self, name: &Group) -> Option<&BTreeSet<URef>> {
318        self.0.get(name)
319    }
320
321    /// Returns a mutable reference to the collection of `URef`s under the given `name` if any.
322    pub fn get_mut(&mut self, name: &Group) -> Option<&mut BTreeSet<URef>> {
323        self.0.get_mut(name)
324    }
325
326    /// Returns the number of named groups.
327    pub fn len(&self) -> usize {
328        self.0.len()
329    }
330
331    /// Returns `true` if there are no named groups.
332    pub fn is_empty(&self) -> bool {
333        self.0.is_empty()
334    }
335
336    /// Returns an iterator over the `Key`s (i.e. the map's values).
337    pub fn keys(&self) -> impl Iterator<Item = &BTreeSet<URef>> {
338        self.0.values()
339    }
340
341    /// Returns the total number of `URef`s contained in all the groups.
342    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/// A newtype wrapping a `HashAddr` which references a [`Package`] in the global state.
388#[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    /// Constructs a new `PackageHash` from the raw bytes of the package hash.
401    pub const fn new(value: HashAddr) -> PackageHash {
402        PackageHash(value)
403    }
404
405    /// Returns the raw bytes of the entity hash as an array.
406    pub fn value(&self) -> HashAddr {
407        self.0
408    }
409
410    /// Returns the raw bytes of the entity hash as a `slice`.
411    pub fn as_bytes(&self) -> &[u8] {
412        &self.0
413    }
414
415    /// Formats the `PackageHash` for users getting and putting.
416    pub fn to_formatted_string(self) -> String {
417        format!("{}{}", PACKAGE_STRING_PREFIX, base16::encode_lower(&self.0),)
418    }
419
420    /// Parses a string formatted as per `Self::to_formatted_string()` into a
421    /// `PackageHash`.
422    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    /// Parses a `PublicKey` and outputs the corresponding account hash.
432    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        // Prepare preimage based on the public key parameters.
448        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        // Hash the preimage data using blake2b256 and return it.
456        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/// A enum to determine the lock status of the package.
565#[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    /// The package is locked and cannot be versioned.
570    Locked,
571    /// The package is unlocked and can be versioned.
572    Unlocked,
573}
574
575impl PackageStatus {
576    /// Create a new status flag based on a boolean value
577    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/// Entity definition, metadata, and security container.
627#[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    /// All versions (enabled & disabled).
632    versions: EntityVersions,
633    /// Collection of disabled entity versions. The runtime will not permit disabled entity
634    /// versions to be executed.
635    disabled_versions: BTreeSet<EntityVersionKey>,
636    /// Mapping maintaining the set of URefs associated with each "user group". This can be used to
637    /// control access to methods in a particular version of the entity. A method is callable by
638    /// any context which "knows" any of the URefs associated with the method's user group.
639    groups: Groups,
640    /// A flag that determines whether a entity is locked
641    lock_status: PackageStatus,
642}
643
644impl CLTyped for Package {
645    fn cl_type() -> CLType {
646        CLType::Any
647    }
648}
649
650impl Package {
651    /// Create new `Package` (with no versions) from given access key.
652    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    /// Enable the entity version corresponding to the given hash (if it exists).
667    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    /// Get the mutable group definitions for this entity.
679    pub fn groups_mut(&mut self) -> &mut Groups {
680        &mut self.groups
681    }
682
683    /// Get the group definitions for this entity.
684    pub fn groups(&self) -> &Groups {
685        &self.groups
686    }
687
688    /// Adds new group to this entity.
689    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    /// Lookup the entity hash for a given entity version (if present)
695    pub fn lookup_entity_hash(&self, entity_version_key: EntityVersionKey) -> Option<&EntityAddr> {
696        self.versions.0.get(&entity_version_key)
697    }
698
699    /// Checks if the given entity version exists.
700    pub fn is_version_missing(&self, entity_version_key: EntityVersionKey) -> bool {
701        !self.versions.0.contains_key(&entity_version_key)
702    }
703
704    /// Checks if the given entity version exists and is available for use.
705    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    /// Returns `true` if the given entity hash exists and is enabled.
711    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    /// Insert a new entity version; the next sequential version number will be issued.
719    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    /// Disable the entity version corresponding to the given hash (if it exists).
731    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    /// Returns reference to all of this entity's versions.
759    pub fn versions(&self) -> &EntityVersions {
760        &self.versions
761    }
762
763    /// Returns all of this entity's enabled entity versions.
764    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    /// Returns mutable reference to all of this entity's versions (enabled and disabled).
776    pub fn versions_mut(&mut self) -> &mut EntityVersions {
777        &mut self.versions
778    }
779
780    /// Consumes the object and returns all of this entity's versions (enabled and disabled).
781    pub fn take_versions(self) -> EntityVersions {
782        self.versions
783    }
784
785    /// Returns all of this entity's disabled versions.
786    pub fn disabled_versions(&self) -> &BTreeSet<EntityVersionKey> {
787        &self.disabled_versions
788    }
789
790    /// Returns mut reference to all of this entity's disabled versions.
791    pub fn disabled_versions_mut(&mut self) -> &mut BTreeSet<EntityVersionKey> {
792        &mut self.disabled_versions
793    }
794
795    /// Removes a group from this entity (if it exists).
796    pub fn remove_group(&mut self, group: &Group) -> bool {
797        self.groups.0.remove(group).is_some()
798    }
799
800    /// Gets the next available entity version for the given protocol version
801    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    /// Return the entity version key for the newest enabled entity version.
841    pub fn current_entity_version(&self) -> Option<EntityVersionKey> {
842        self.enabled_versions().0.keys().next_back().copied()
843    }
844
845    /// Return the entity hash for the newest enabled entity version.
846    pub fn current_entity_hash(&self) -> Option<EntityAddr> {
847        self.enabled_versions().0.values().next_back().copied()
848    }
849
850    /// Return the lock status of the entity package.
851    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    /// Return the package status itself
863    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        // add groups
933        {
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        // add entry_points
950        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"))); // Group no longer exists
1024    }
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        // This was once true, but look up vs disable checking have been decoupled in 2.0
1095        // assert_eq!(
1096        //     package.lookup_entity_hash(next_version),
1097        //     None,
1098        //     "should not return disabled entity version"
1099        // );
1100        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}