casper_types/
addressable_entity.rs

1//! Data types for supporting contract headers feature.
2// TODO - remove once schemars stops causing warning.
3#![allow(clippy::field_reassign_with_default)]
4
5pub mod action_thresholds;
6mod action_type;
7pub mod associated_keys;
8mod entry_points;
9mod error;
10//mod named_keys;
11mod weight;
12
13use alloc::{
14    collections::{btree_map::Entry, BTreeMap, BTreeSet},
15    format,
16    string::{String, ToString},
17    vec::Vec,
18};
19use blake2::{
20    digest::{Update, VariableOutput},
21    VarBlake2b,
22};
23use core::{
24    array::TryFromSliceError,
25    convert::{TryFrom, TryInto},
26    fmt::{self, Debug, Display, Formatter},
27    iter,
28};
29
30#[cfg(feature = "json-schema")]
31use crate::SecretKey;
32#[cfg(feature = "datasize")]
33use datasize::DataSize;
34#[cfg(feature = "json-schema")]
35use once_cell::sync::Lazy;
36#[cfg(any(feature = "testing", test))]
37use rand::{
38    distributions::{Distribution, Standard},
39    Rng,
40};
41#[cfg(feature = "json-schema")]
42use schemars::JsonSchema;
43use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
44#[cfg(feature = "json-schema")]
45use serde_map_to_array::KeyValueJsonSchema;
46use serde_map_to_array::{BTreeMapToArray, KeyValueLabels};
47
48pub use self::{
49    action_thresholds::ActionThresholds,
50    action_type::ActionType,
51    associated_keys::AssociatedKeys,
52    entry_points::{
53        EntityEntryPoint, EntryPointAccess, EntryPointAddr, EntryPointPayment, EntryPointType,
54        EntryPointValue, EntryPoints, Parameter, Parameters, DEFAULT_ENTRY_POINT_NAME,
55    },
56    error::{FromAccountHashStrError, TryFromIntError, TryFromSliceForAccountHashError},
57    weight::{Weight, WEIGHT_SERIALIZED_LENGTH},
58};
59use crate::{
60    account::{
61        Account, AccountHash, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure,
62        UpdateKeyFailure,
63    },
64    byte_code::ByteCodeHash,
65    bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
66    checksummed_hex,
67    contract_messages::TopicNameHash,
68    contracts::{Contract, ContractHash},
69    system::SystemEntityType,
70    uref::{self, URef},
71    AccessRights, ApiError, CLType, CLTyped, CLValue, CLValueError, ContextAccessRights, HashAddr,
72    Key, NamedKeys, PackageHash, ProtocolVersion, PublicKey, Tagged, BLAKE2B_DIGEST_LENGTH,
73    KEY_HASH_LENGTH,
74};
75
76/// Maximum number of distinct user groups.
77pub const MAX_GROUPS: u8 = 10;
78/// Maximum number of URefs which can be assigned across all user groups.
79pub const MAX_TOTAL_UREFS: usize = 100;
80
81/// The prefix applied to the hex-encoded `Addressable Entity` to produce a formatted string
82/// representation.
83pub const ADDRESSABLE_ENTITY_STRING_PREFIX: &str = "addressable-entity-";
84/// The prefix applied to the hex-encoded `Entity` to produce a formatted string
85/// representation.
86pub const ENTITY_PREFIX: &str = "entity-";
87/// The prefix applied to the hex-encoded `Account` to produce a formatted string
88/// representation.
89pub const ACCOUNT_ENTITY_PREFIX: &str = "account-";
90/// The prefix applied to the hex-encoded `Smart contract` to produce a formatted string
91/// representation.
92pub const CONTRACT_ENTITY_PREFIX: &str = "contract-";
93/// The prefix applied to the hex-encoded `System entity account or contract` to produce a formatted
94///  string representation.
95pub const SYSTEM_ENTITY_PREFIX: &str = "system-";
96/// The prefix applied to the hex-encoded `Named Key` to produce a formatted string
97/// representation.
98pub const NAMED_KEY_PREFIX: &str = "named-key-";
99
100/// Set of errors which may happen when working with contract headers.
101#[derive(Debug, PartialEq, Eq)]
102#[repr(u8)]
103#[non_exhaustive]
104pub enum Error {
105    /// Attempt to override an existing or previously existing version with a
106    /// new header (this is not allowed to ensure immutability of a given
107    /// version).
108    /// ```
109    /// # use casper_types::addressable_entity::Error;
110    /// assert_eq!(1, Error::PreviouslyUsedVersion as u8);
111    /// ```
112    PreviouslyUsedVersion = 1,
113    /// Attempted to disable a contract that does not exist.
114    /// ```
115    /// # use casper_types::addressable_entity::Error;
116    /// assert_eq!(2, Error::EntityNotFound as u8);
117    /// ```
118    EntityNotFound = 2,
119    /// Attempted to create a user group which already exists (use the update
120    /// function to change an existing user group).
121    /// ```
122    /// # use casper_types::addressable_entity::Error;
123    /// assert_eq!(3, Error::GroupAlreadyExists as u8);
124    /// ```
125    GroupAlreadyExists = 3,
126    /// Attempted to add a new user group which exceeds the allowed maximum
127    /// number of groups.
128    /// ```
129    /// # use casper_types::addressable_entity::Error;
130    /// assert_eq!(4, Error::MaxGroupsExceeded as u8);
131    /// ```
132    MaxGroupsExceeded = 4,
133    /// Attempted to add a new URef to a group, which resulted in the total
134    /// number of URefs across all user groups to exceed the allowed maximum.
135    /// ```
136    /// # use casper_types::addressable_entity::Error;
137    /// assert_eq!(5, Error::MaxTotalURefsExceeded as u8);
138    /// ```
139    MaxTotalURefsExceeded = 5,
140    /// Attempted to remove a URef from a group, which does not exist in the
141    /// group.
142    /// ```
143    /// # use casper_types::addressable_entity::Error;
144    /// assert_eq!(6, Error::GroupDoesNotExist as u8);
145    /// ```
146    GroupDoesNotExist = 6,
147    /// Attempted to remove unknown URef from the group.
148    /// ```
149    /// # use casper_types::addressable_entity::Error;
150    /// assert_eq!(7, Error::UnableToRemoveURef as u8);
151    /// ```
152    UnableToRemoveURef = 7,
153    /// Group is use by at least one active contract.
154    /// ```
155    /// # use casper_types::addressable_entity::Error;
156    /// assert_eq!(8, Error::GroupInUse as u8);
157    /// ```
158    GroupInUse = 8,
159    /// URef already exists in given group.
160    /// ```
161    /// # use casper_types::addressable_entity::Error;
162    /// assert_eq!(9, Error::URefAlreadyExists as u8);
163    /// ```
164    URefAlreadyExists = 9,
165}
166
167impl TryFrom<u8> for Error {
168    type Error = ();
169
170    fn try_from(value: u8) -> Result<Self, Self::Error> {
171        let error = match value {
172            v if v == Self::PreviouslyUsedVersion as u8 => Self::PreviouslyUsedVersion,
173            v if v == Self::EntityNotFound as u8 => Self::EntityNotFound,
174            v if v == Self::GroupAlreadyExists as u8 => Self::GroupAlreadyExists,
175            v if v == Self::MaxGroupsExceeded as u8 => Self::MaxGroupsExceeded,
176            v if v == Self::MaxTotalURefsExceeded as u8 => Self::MaxTotalURefsExceeded,
177            v if v == Self::GroupDoesNotExist as u8 => Self::GroupDoesNotExist,
178            v if v == Self::UnableToRemoveURef as u8 => Self::UnableToRemoveURef,
179            v if v == Self::GroupInUse as u8 => Self::GroupInUse,
180            v if v == Self::URefAlreadyExists as u8 => Self::URefAlreadyExists,
181            _ => return Err(()),
182        };
183        Ok(error)
184    }
185}
186
187/// Associated error type of `TryFrom<&[u8]>` for `ContractHash`.
188#[derive(Debug)]
189pub struct TryFromSliceForContractHashError(());
190
191impl Display for TryFromSliceForContractHashError {
192    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
193        write!(f, "failed to retrieve from slice")
194    }
195}
196
197/// An error from parsing a formatted contract string
198#[derive(Debug)]
199#[non_exhaustive]
200pub enum FromStrError {
201    /// Invalid formatted string prefix.
202    InvalidPrefix,
203    /// Error when decoding a hex string
204    Hex(base16::DecodeError),
205    /// Error when parsing an account
206    Account(TryFromSliceForAccountHashError),
207    /// Error when parsing the hash.
208    Hash(TryFromSliceError),
209    /// Error when parsing an uref.
210    URef(uref::FromStrError),
211    /// Error parsing from bytes.
212    BytesRepr(bytesrepr::Error),
213}
214
215impl From<base16::DecodeError> for FromStrError {
216    fn from(error: base16::DecodeError) -> Self {
217        FromStrError::Hex(error)
218    }
219}
220
221impl From<TryFromSliceError> for FromStrError {
222    fn from(error: TryFromSliceError) -> Self {
223        FromStrError::Hash(error)
224    }
225}
226
227impl From<uref::FromStrError> for FromStrError {
228    fn from(error: uref::FromStrError) -> Self {
229        FromStrError::URef(error)
230    }
231}
232
233impl Display for FromStrError {
234    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
235        match self {
236            FromStrError::InvalidPrefix => write!(f, "invalid prefix"),
237            FromStrError::Hex(error) => write!(f, "decode from hex: {}", error),
238            FromStrError::Hash(error) => write!(f, "hash from string error: {}", error),
239            FromStrError::URef(error) => write!(f, "uref from string error: {:?}", error),
240            FromStrError::Account(error) => {
241                write!(f, "account hash from string error: {:?}", error)
242            }
243            FromStrError::BytesRepr(error) => {
244                write!(f, "bytesrepr error: {:?}", error)
245            }
246        }
247    }
248}
249
250/// A newtype wrapping a `HashAddr` which references an [`AddressableEntity`] in the global state.
251#[derive(Default, PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy)]
252#[cfg_attr(feature = "datasize", derive(DataSize))]
253#[cfg_attr(
254    feature = "json-schema",
255    derive(JsonSchema),
256    schemars(description = "The hex-encoded address of the addressable entity.")
257)]
258pub struct AddressableEntityHash(
259    #[cfg_attr(feature = "json-schema", schemars(skip, with = "String"))] HashAddr,
260);
261
262impl AddressableEntityHash {
263    /// Constructs a new `AddressableEntityHash` from the raw bytes of the contract hash.
264    pub const fn new(value: HashAddr) -> AddressableEntityHash {
265        AddressableEntityHash(value)
266    }
267
268    /// Get the entity addr for this entity hash from the corresponding entity.
269    pub fn entity_addr(&self, entity: AddressableEntity) -> EntityAddr {
270        entity.entity_addr(*self)
271    }
272
273    /// Returns the raw bytes of the contract hash as an array.
274    pub fn value(&self) -> HashAddr {
275        self.0
276    }
277
278    /// Returns the raw bytes of the contract hash as a `slice`.
279    pub fn as_bytes(&self) -> &[u8] {
280        &self.0
281    }
282
283    /// Formats the `AddressableEntityHash` for users getting and putting.
284    pub fn to_formatted_string(self) -> String {
285        format!(
286            "{}{}",
287            ADDRESSABLE_ENTITY_STRING_PREFIX,
288            base16::encode_lower(&self.0),
289        )
290    }
291
292    /// Hexadecimal representation of the hash.
293    pub fn to_hex_string(&self) -> String {
294        base16::encode_lower(&self.0)
295    }
296
297    /// Parses a string formatted as per `Self::to_formatted_string()` into a
298    /// `AddressableEntityHash`.
299    pub fn from_formatted_str(input: &str) -> Result<Self, FromStrError> {
300        let remainder = input
301            .strip_prefix(ADDRESSABLE_ENTITY_STRING_PREFIX)
302            .ok_or(FromStrError::InvalidPrefix)?;
303        let bytes = HashAddr::try_from(checksummed_hex::decode(remainder)?.as_ref())?;
304        Ok(AddressableEntityHash(bytes))
305    }
306}
307
308impl From<ContractHash> for AddressableEntityHash {
309    fn from(contract_hash: ContractHash) -> Self {
310        AddressableEntityHash::new(contract_hash.value())
311    }
312}
313
314impl Display for AddressableEntityHash {
315    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
316        write!(f, "{}", base16::encode_lower(&self.0))
317    }
318}
319
320impl Debug for AddressableEntityHash {
321    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
322        write!(
323            f,
324            "AddressableEntityHash({})",
325            base16::encode_lower(&self.0)
326        )
327    }
328}
329
330impl CLTyped for AddressableEntityHash {
331    fn cl_type() -> CLType {
332        CLType::ByteArray(KEY_HASH_LENGTH as u32)
333    }
334}
335
336impl ToBytes for AddressableEntityHash {
337    #[inline(always)]
338    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
339        self.0.to_bytes()
340    }
341
342    #[inline(always)]
343    fn serialized_length(&self) -> usize {
344        self.0.serialized_length()
345    }
346
347    #[inline(always)]
348    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
349        writer.extend_from_slice(&self.0);
350        Ok(())
351    }
352}
353
354impl FromBytes for AddressableEntityHash {
355    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
356        let (bytes, rem) = FromBytes::from_bytes(bytes)?;
357        Ok((AddressableEntityHash::new(bytes), rem))
358    }
359}
360
361impl From<[u8; 32]> for AddressableEntityHash {
362    fn from(bytes: [u8; 32]) -> Self {
363        AddressableEntityHash(bytes)
364    }
365}
366
367impl TryFrom<Key> for AddressableEntityHash {
368    type Error = ApiError;
369
370    fn try_from(value: Key) -> Result<Self, Self::Error> {
371        if let Key::AddressableEntity(entity_addr) = value {
372            Ok(AddressableEntityHash::new(entity_addr.value()))
373        } else {
374            Err(ApiError::Formatting)
375        }
376    }
377}
378
379impl Serialize for AddressableEntityHash {
380    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
381        if serializer.is_human_readable() {
382            self.to_formatted_string().serialize(serializer)
383        } else {
384            self.0.serialize(serializer)
385        }
386    }
387}
388
389impl<'de> Deserialize<'de> for AddressableEntityHash {
390    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
391        if deserializer.is_human_readable() {
392            let formatted_string = String::deserialize(deserializer)?;
393            AddressableEntityHash::from_formatted_str(&formatted_string).map_err(SerdeError::custom)
394        } else {
395            let bytes = HashAddr::deserialize(deserializer)?;
396            Ok(AddressableEntityHash(bytes))
397        }
398    }
399}
400
401impl AsRef<[u8]> for AddressableEntityHash {
402    fn as_ref(&self) -> &[u8] {
403        self.0.as_ref()
404    }
405}
406
407impl TryFrom<&[u8]> for AddressableEntityHash {
408    type Error = TryFromSliceForContractHashError;
409
410    fn try_from(bytes: &[u8]) -> Result<Self, TryFromSliceForContractHashError> {
411        HashAddr::try_from(bytes)
412            .map(AddressableEntityHash::new)
413            .map_err(|_| TryFromSliceForContractHashError(()))
414    }
415}
416
417impl TryFrom<&Vec<u8>> for AddressableEntityHash {
418    type Error = TryFromSliceForContractHashError;
419
420    fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
421        HashAddr::try_from(bytes as &[u8])
422            .map(AddressableEntityHash::new)
423            .map_err(|_| TryFromSliceForContractHashError(()))
424    }
425}
426
427#[cfg(any(feature = "testing", test))]
428impl Distribution<AddressableEntityHash> for Standard {
429    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AddressableEntityHash {
430        AddressableEntityHash(rng.gen())
431    }
432}
433
434/// Tag for the variants of [`EntityKind`].
435#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
436#[cfg_attr(feature = "datasize", derive(DataSize))]
437#[repr(u8)]
438pub enum EntityKindTag {
439    /// `EntityKind::System` variant.
440    System = 0,
441    /// `EntityKind::Account` variant.
442    Account = 1,
443    /// `EntityKind::SmartContract` variant.
444    SmartContract = 2,
445}
446
447impl TryFrom<u8> for EntityKindTag {
448    type Error = bytesrepr::Error;
449
450    fn try_from(value: u8) -> Result<Self, Self::Error> {
451        match value {
452            0 => Ok(EntityKindTag::System),
453            1 => Ok(EntityKindTag::Account),
454            2 => Ok(EntityKindTag::SmartContract),
455            _ => Err(bytesrepr::Error::Formatting),
456        }
457    }
458}
459
460impl ToBytes for EntityKindTag {
461    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
462        (*self as u8).to_bytes()
463    }
464
465    fn serialized_length(&self) -> usize {
466        U8_SERIALIZED_LENGTH
467    }
468
469    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
470        (*self as u8).write_bytes(writer)
471    }
472}
473
474impl FromBytes for EntityKindTag {
475    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
476        let (entity_kind_tag, remainder) = u8::from_bytes(bytes)?;
477        Ok((entity_kind_tag.try_into()?, remainder))
478    }
479}
480
481impl Display for EntityKindTag {
482    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
483        match self {
484            EntityKindTag::System => {
485                write!(f, "system")
486            }
487            EntityKindTag::Account => {
488                write!(f, "account")
489            }
490            EntityKindTag::SmartContract => {
491                write!(f, "contract")
492            }
493        }
494    }
495}
496
497#[cfg(any(feature = "testing", test))]
498impl Distribution<EntityKindTag> for Standard {
499    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> EntityKindTag {
500        match rng.gen_range(0..=2) {
501            0 => EntityKindTag::System,
502            1 => EntityKindTag::Account,
503            2 => EntityKindTag::SmartContract,
504            _ => unreachable!(),
505        }
506    }
507}
508
509#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, Debug)]
510#[cfg_attr(feature = "datasize", derive(DataSize))]
511#[cfg_attr(
512    feature = "json-schema",
513    derive(JsonSchema),
514    schemars(description = "Runtime used to execute a Transaction.")
515)]
516//Default is needed only in testing to meet EnumIter needs
517#[cfg_attr(any(feature = "testing", test), derive(Default))]
518#[serde(deny_unknown_fields)]
519#[repr(u8)]
520pub enum ContractRuntimeTag {
521    #[cfg_attr(any(feature = "testing", test), default)]
522    VmCasperV1,
523    VmCasperV2,
524}
525
526#[cfg(any(feature = "testing", test))]
527impl Distribution<ContractRuntimeTag> for Standard {
528    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ContractRuntimeTag {
529        match rng.gen_range(0..=1) {
530            0 => ContractRuntimeTag::VmCasperV1,
531            1 => ContractRuntimeTag::VmCasperV2,
532            _ => unreachable!(),
533        }
534    }
535}
536
537impl ToBytes for ContractRuntimeTag {
538    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
539        (*self as u8).to_bytes()
540    }
541
542    fn serialized_length(&self) -> usize {
543        U8_SERIALIZED_LENGTH
544    }
545
546    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
547        (*self as u8).write_bytes(writer)
548    }
549}
550
551impl FromBytes for ContractRuntimeTag {
552    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
553        let (tag, remainder) = u8::from_bytes(bytes)?;
554        if tag == ContractRuntimeTag::VmCasperV1 as u8 {
555            Ok((ContractRuntimeTag::VmCasperV1, remainder))
556        } else if tag == ContractRuntimeTag::VmCasperV2 as u8 {
557            Ok((ContractRuntimeTag::VmCasperV2, remainder))
558        } else {
559            Err(bytesrepr::Error::Formatting)
560        }
561    }
562}
563
564impl Display for ContractRuntimeTag {
565    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
566        match self {
567            ContractRuntimeTag::VmCasperV1 => write!(f, "vm-casper-v1"),
568            ContractRuntimeTag::VmCasperV2 => write!(f, "vm-casper-v2"),
569        }
570    }
571}
572impl ContractRuntimeTag {
573    /// Returns the tag of the [`ContractRuntimeTag`].
574    pub fn tag(&self) -> u8 {
575        *self as u8
576    }
577}
578
579#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
580#[cfg_attr(feature = "datasize", derive(DataSize))]
581#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
582/// The type of Package.
583pub enum EntityKind {
584    /// Package associated with a native contract implementation.
585    System(SystemEntityType),
586    /// Package associated with an Account hash.
587    Account(AccountHash),
588    /// Packages associated with Wasm stored on chain.
589    SmartContract(ContractRuntimeTag),
590}
591
592impl EntityKind {
593    /// Returns the Account hash associated with a Package based on the package kind.
594    pub fn maybe_account_hash(&self) -> Option<AccountHash> {
595        match self {
596            Self::Account(account_hash) => Some(*account_hash),
597            Self::SmartContract(_) | Self::System(_) => None,
598        }
599    }
600
601    /// Returns the associated key set based on the Account hash set in the package kind.
602    pub fn associated_keys(&self) -> AssociatedKeys {
603        match self {
604            Self::Account(account_hash) => AssociatedKeys::new(*account_hash, Weight::new(1)),
605            Self::SmartContract(_) | Self::System(_) => AssociatedKeys::default(),
606        }
607    }
608
609    /// Returns if the current package is either a system contract or the system entity.
610    pub fn is_system(&self) -> bool {
611        matches!(self, Self::System(_))
612    }
613
614    /// Returns if the current package is the system mint.
615    pub fn is_system_mint(&self) -> bool {
616        matches!(self, Self::System(SystemEntityType::Mint))
617    }
618
619    /// Returns if the current package is the system auction.
620    pub fn is_system_auction(&self) -> bool {
621        matches!(self, Self::System(SystemEntityType::Auction))
622    }
623
624    /// Returns if the current package is associated with the system addressable entity.
625    pub fn is_system_account(&self) -> bool {
626        match self {
627            Self::Account(account_hash) => {
628                if *account_hash == PublicKey::System.to_account_hash() {
629                    return true;
630                }
631                false
632            }
633            _ => false,
634        }
635    }
636}
637
638impl Tagged<EntityKindTag> for EntityKind {
639    fn tag(&self) -> EntityKindTag {
640        match self {
641            EntityKind::System(_) => EntityKindTag::System,
642            EntityKind::Account(_) => EntityKindTag::Account,
643            EntityKind::SmartContract(_) => EntityKindTag::SmartContract,
644        }
645    }
646}
647
648impl Tagged<u8> for EntityKind {
649    fn tag(&self) -> u8 {
650        let package_kind_tag: EntityKindTag = self.tag();
651        package_kind_tag as u8
652    }
653}
654
655impl ToBytes for EntityKind {
656    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
657        let mut buffer = bytesrepr::allocate_buffer(self)?;
658        self.write_bytes(&mut buffer)?;
659        Ok(buffer)
660    }
661
662    fn serialized_length(&self) -> usize {
663        U8_SERIALIZED_LENGTH
664            + match self {
665                EntityKind::SmartContract(transaction_runtime) => {
666                    transaction_runtime.serialized_length()
667                }
668                EntityKind::System(system_entity_type) => system_entity_type.serialized_length(),
669                EntityKind::Account(account_hash) => account_hash.serialized_length(),
670            }
671    }
672
673    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
674        match self {
675            EntityKind::SmartContract(transaction_runtime) => {
676                writer.push(self.tag());
677                transaction_runtime.write_bytes(writer)
678            }
679            EntityKind::System(system_entity_type) => {
680                writer.push(self.tag());
681                system_entity_type.write_bytes(writer)
682            }
683            EntityKind::Account(account_hash) => {
684                writer.push(self.tag());
685                account_hash.write_bytes(writer)
686            }
687        }
688    }
689}
690
691impl FromBytes for EntityKind {
692    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
693        let (tag, remainder) = EntityKindTag::from_bytes(bytes)?;
694        match tag {
695            EntityKindTag::System => {
696                let (entity_type, remainder) = SystemEntityType::from_bytes(remainder)?;
697                Ok((EntityKind::System(entity_type), remainder))
698            }
699            EntityKindTag::Account => {
700                let (account_hash, remainder) = AccountHash::from_bytes(remainder)?;
701                Ok((EntityKind::Account(account_hash), remainder))
702            }
703            EntityKindTag::SmartContract => {
704                let (transaction_runtime, remainder) = FromBytes::from_bytes(remainder)?;
705                Ok((EntityKind::SmartContract(transaction_runtime), remainder))
706            }
707        }
708    }
709}
710
711impl Display for EntityKind {
712    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
713        match self {
714            EntityKind::System(system_entity) => {
715                write!(f, "system-entity-kind({})", system_entity)
716            }
717            EntityKind::Account(account_hash) => {
718                write!(f, "account-entity-kind({})", account_hash)
719            }
720            EntityKind::SmartContract(transaction_runtime) => {
721                write!(f, "smart-contract-entity-kind({})", transaction_runtime)
722            }
723        }
724    }
725}
726
727#[cfg(any(feature = "testing", test))]
728impl Distribution<EntityKind> for Standard {
729    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> EntityKind {
730        match rng.gen_range(0..=2) {
731            0 => EntityKind::System(rng.gen()),
732            1 => EntityKind::Account(rng.gen()),
733            2 => EntityKind::SmartContract(rng.gen()),
734            _ => unreachable!(),
735        }
736    }
737}
738
739/// The address for an AddressableEntity which contains the 32 bytes and tagging information.
740#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy)]
741#[cfg_attr(feature = "datasize", derive(DataSize))]
742#[cfg_attr(feature = "json-schema", derive(JsonSchema), schemars(untagged))]
743pub enum EntityAddr {
744    /// The address for a system entity account or contract.
745    System(#[cfg_attr(feature = "json-schema", schemars(skip, with = "String"))] HashAddr),
746    /// The address of an entity that corresponds to an Account.
747    Account(#[cfg_attr(feature = "json-schema", schemars(skip, with = "String"))] HashAddr),
748    /// The address of an entity that corresponds to a Userland smart contract.
749    SmartContract(#[cfg_attr(feature = "json-schema", schemars(skip, with = "String"))] HashAddr),
750}
751
752impl EntityAddr {
753    /// The length in bytes of an `EntityAddr`.
754    pub const LENGTH: usize = U8_SERIALIZED_LENGTH + KEY_HASH_LENGTH;
755
756    /// Constructs a new `EntityAddr` for a system entity.
757    pub const fn new_system(hash_addr: HashAddr) -> Self {
758        Self::System(hash_addr)
759    }
760
761    /// Constructs a new `EntityAddr` for an Account entity.
762    pub const fn new_account(hash_addr: HashAddr) -> Self {
763        Self::Account(hash_addr)
764    }
765
766    /// Constructs a new `EntityAddr` for a smart contract.
767    pub const fn new_smart_contract(hash_addr: HashAddr) -> Self {
768        Self::SmartContract(hash_addr)
769    }
770
771    /// Constructs a new `EntityAddr` based on the supplied kind.
772    pub fn new_of_kind(entity_kind: EntityKind, hash_addr: HashAddr) -> Self {
773        match entity_kind {
774            EntityKind::System(_) => Self::new_system(hash_addr),
775            EntityKind::Account(_) => Self::new_account(hash_addr),
776            EntityKind::SmartContract(_) => Self::new_smart_contract(hash_addr),
777        }
778    }
779
780    /// Returns the tag of the [`EntityAddr`].
781    pub fn tag(&self) -> EntityKindTag {
782        match self {
783            EntityAddr::System(_) => EntityKindTag::System,
784            EntityAddr::Account(_) => EntityKindTag::Account,
785            EntityAddr::SmartContract(_) => EntityKindTag::SmartContract,
786        }
787    }
788
789    /// Is this a system entity address?
790    pub fn is_system(&self) -> bool {
791        self.tag() == EntityKindTag::System
792            || self.value() == PublicKey::System.to_account_hash().value()
793    }
794
795    /// Is this a contract entity address?
796    pub fn is_contract(&self) -> bool {
797        self.tag() == EntityKindTag::SmartContract
798    }
799
800    /// Is this an account entity address?
801    pub fn is_account(&self) -> bool {
802        self.tag() == EntityKindTag::Account
803    }
804
805    /// Returns the 32 bytes of the [`EntityAddr`].
806    pub fn value(&self) -> HashAddr {
807        match self {
808            EntityAddr::System(hash_addr)
809            | EntityAddr::Account(hash_addr)
810            | EntityAddr::SmartContract(hash_addr) => *hash_addr,
811        }
812    }
813
814    /// Returns the formatted String representation of the [`EntityAddr`].
815    pub fn to_formatted_string(&self) -> String {
816        match self {
817            EntityAddr::System(addr) => {
818                format!(
819                    "{}{}{}",
820                    ENTITY_PREFIX,
821                    SYSTEM_ENTITY_PREFIX,
822                    base16::encode_lower(addr)
823                )
824            }
825            EntityAddr::Account(addr) => {
826                format!(
827                    "{}{}{}",
828                    ENTITY_PREFIX,
829                    ACCOUNT_ENTITY_PREFIX,
830                    base16::encode_lower(addr)
831                )
832            }
833            EntityAddr::SmartContract(addr) => {
834                format!(
835                    "{}{}{}",
836                    ENTITY_PREFIX,
837                    CONTRACT_ENTITY_PREFIX,
838                    base16::encode_lower(addr)
839                )
840            }
841        }
842    }
843
844    /// Constructs an [`EntityAddr`] from a formatted String.
845    pub fn from_formatted_str(input: &str) -> Result<Self, FromStrError> {
846        if let Some(entity) = input.strip_prefix(ENTITY_PREFIX) {
847            let (addr_str, tag) = if let Some(str) = entity.strip_prefix(SYSTEM_ENTITY_PREFIX) {
848                (str, EntityKindTag::System)
849            } else if let Some(str) = entity.strip_prefix(ACCOUNT_ENTITY_PREFIX) {
850                (str, EntityKindTag::Account)
851            } else if let Some(str) = entity.strip_prefix(CONTRACT_ENTITY_PREFIX) {
852                (str, EntityKindTag::SmartContract)
853            } else {
854                return Err(FromStrError::InvalidPrefix);
855            };
856            let addr = checksummed_hex::decode(addr_str).map_err(FromStrError::Hex)?;
857            let hash_addr = HashAddr::try_from(addr.as_ref()).map_err(FromStrError::Hash)?;
858            let entity_addr = match tag {
859                EntityKindTag::System => EntityAddr::new_system(hash_addr),
860                EntityKindTag::Account => EntityAddr::new_account(hash_addr),
861                EntityKindTag::SmartContract => EntityAddr::new_smart_contract(hash_addr),
862            };
863
864            return Ok(entity_addr);
865        }
866
867        Err(FromStrError::InvalidPrefix)
868    }
869
870    pub fn into_smart_contract(&self) -> Option<[u8; 32]> {
871        match self {
872            EntityAddr::SmartContract(addr) => Some(*addr),
873            _ => None,
874        }
875    }
876}
877
878impl ToBytes for EntityAddr {
879    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
880        let mut buffer = bytesrepr::allocate_buffer(self)?;
881        self.write_bytes(&mut buffer)?;
882        Ok(buffer)
883    }
884
885    fn serialized_length(&self) -> usize {
886        EntityAddr::LENGTH
887    }
888
889    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
890        match self {
891            EntityAddr::System(addr) => {
892                EntityKindTag::System.write_bytes(writer)?;
893                addr.write_bytes(writer)
894            }
895            EntityAddr::Account(addr) => {
896                EntityKindTag::Account.write_bytes(writer)?;
897                addr.write_bytes(writer)
898            }
899            EntityAddr::SmartContract(addr) => {
900                EntityKindTag::SmartContract.write_bytes(writer)?;
901                addr.write_bytes(writer)
902            }
903        }
904    }
905}
906
907impl FromBytes for EntityAddr {
908    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
909        let (tag, remainder) = EntityKindTag::from_bytes(bytes)?;
910        let (addr, remainder) = HashAddr::from_bytes(remainder)?;
911        let entity_addr = match tag {
912            EntityKindTag::System => EntityAddr::System(addr),
913            EntityKindTag::Account => EntityAddr::Account(addr),
914            EntityKindTag::SmartContract => EntityAddr::SmartContract(addr),
915        };
916        Ok((entity_addr, remainder))
917    }
918}
919
920impl CLTyped for EntityAddr {
921    fn cl_type() -> CLType {
922        CLType::Any
923    }
924}
925
926impl From<EntityAddr> for AddressableEntityHash {
927    fn from(entity_addr: EntityAddr) -> Self {
928        AddressableEntityHash::new(entity_addr.value())
929    }
930}
931
932impl Display for EntityAddr {
933    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
934        f.write_str(&self.to_formatted_string())
935    }
936}
937
938impl Debug for EntityAddr {
939    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
940        match self {
941            EntityAddr::System(hash_addr) => {
942                write!(f, "EntityAddr::System({})", base16::encode_lower(hash_addr))
943            }
944            EntityAddr::Account(hash_addr) => {
945                write!(
946                    f,
947                    "EntityAddr::Account({})",
948                    base16::encode_lower(hash_addr)
949                )
950            }
951            EntityAddr::SmartContract(hash_addr) => {
952                write!(
953                    f,
954                    "EntityAddr::SmartContract({})",
955                    base16::encode_lower(hash_addr)
956                )
957            }
958        }
959    }
960}
961
962impl Serialize for EntityAddr {
963    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
964        if serializer.is_human_readable() {
965            self.to_formatted_string().serialize(serializer)
966        } else {
967            let (tag, value): (EntityKindTag, HashAddr) = (self.tag(), self.value());
968            (tag, value).serialize(serializer)
969        }
970    }
971}
972
973impl<'de> Deserialize<'de> for EntityAddr {
974    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
975        if deserializer.is_human_readable() {
976            let formatted_string = String::deserialize(deserializer)?;
977            Self::from_formatted_str(&formatted_string).map_err(SerdeError::custom)
978        } else {
979            let (tag, addr) = <(EntityKindTag, HashAddr)>::deserialize(deserializer)?;
980            match tag {
981                EntityKindTag::System => Ok(EntityAddr::new_system(addr)),
982                EntityKindTag::Account => Ok(EntityAddr::new_account(addr)),
983                EntityKindTag::SmartContract => Ok(EntityAddr::new_smart_contract(addr)),
984            }
985        }
986    }
987}
988
989#[cfg(any(feature = "testing", test))]
990impl Distribution<EntityAddr> for Standard {
991    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> EntityAddr {
992        match rng.gen_range(0..=2) {
993            0 => EntityAddr::System(rng.gen()),
994            1 => EntityAddr::Account(rng.gen()),
995            2 => EntityAddr::SmartContract(rng.gen()),
996            _ => unreachable!(),
997        }
998    }
999}
1000
1001/// A NamedKey address.
1002#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
1003#[cfg_attr(feature = "datasize", derive(DataSize))]
1004#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
1005pub struct NamedKeyAddr {
1006    /// The address of the entity.
1007    base_addr: EntityAddr,
1008    /// The bytes of the name.
1009    string_bytes: [u8; KEY_HASH_LENGTH],
1010}
1011
1012impl NamedKeyAddr {
1013    /// The length in bytes of a [`NamedKeyAddr`].
1014    pub const NAMED_KEY_ADDR_BASE_LENGTH: usize = 1 + EntityAddr::LENGTH;
1015
1016    /// Constructs a new [`NamedKeyAddr`] based on the supplied bytes.
1017    pub const fn new_named_key_entry(
1018        entity_addr: EntityAddr,
1019        string_bytes: [u8; KEY_HASH_LENGTH],
1020    ) -> Self {
1021        Self {
1022            base_addr: entity_addr,
1023            string_bytes,
1024        }
1025    }
1026
1027    /// Constructs a new [`NamedKeyAddr`] based on string name.
1028    /// Will fail if the string cannot be serialized.
1029    pub fn new_from_string(
1030        entity_addr: EntityAddr,
1031        entry: String,
1032    ) -> Result<Self, bytesrepr::Error> {
1033        let bytes = entry.to_bytes()?;
1034        let mut hasher = {
1035            match VarBlake2b::new(BLAKE2B_DIGEST_LENGTH) {
1036                Ok(hasher) => hasher,
1037                Err(_) => return Err(bytesrepr::Error::Formatting),
1038            }
1039        };
1040        hasher.update(bytes);
1041        // NOTE: Assumed safe as size of `HashAddr` equals to the output provided by hasher.
1042        let mut string_bytes = HashAddr::default();
1043        hasher.finalize_variable(|hash| string_bytes.clone_from_slice(hash));
1044        Ok(Self::new_named_key_entry(entity_addr, string_bytes))
1045    }
1046
1047    /// Returns the encapsulated [`EntityAddr`].
1048    pub fn entity_addr(&self) -> EntityAddr {
1049        self.base_addr
1050    }
1051
1052    /// Returns the formatted String representation of the [`NamedKeyAddr`].
1053    pub fn to_formatted_string(&self) -> String {
1054        format!("{}", self)
1055    }
1056
1057    /// Constructs a [`NamedKeyAddr`] from a formatted string.
1058    pub fn from_formatted_str(input: &str) -> Result<Self, FromStrError> {
1059        if let Some(named_key) = input.strip_prefix(NAMED_KEY_PREFIX) {
1060            if let Some((entity_addr_str, string_bytes_str)) = named_key.rsplit_once('-') {
1061                let entity_addr = EntityAddr::from_formatted_str(entity_addr_str)?;
1062                let string_bytes =
1063                    checksummed_hex::decode(string_bytes_str).map_err(FromStrError::Hex)?;
1064                let (string_bytes, _) =
1065                    FromBytes::from_vec(string_bytes).map_err(FromStrError::BytesRepr)?;
1066                return Ok(Self::new_named_key_entry(entity_addr, string_bytes));
1067            };
1068        }
1069
1070        Err(FromStrError::InvalidPrefix)
1071    }
1072}
1073
1074impl Default for NamedKeyAddr {
1075    fn default() -> Self {
1076        NamedKeyAddr {
1077            base_addr: EntityAddr::System(HashAddr::default()),
1078            string_bytes: Default::default(),
1079        }
1080    }
1081}
1082
1083impl ToBytes for NamedKeyAddr {
1084    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
1085        let mut buffer = bytesrepr::allocate_buffer(self)?;
1086        buffer.append(&mut self.base_addr.to_bytes()?);
1087        buffer.append(&mut self.string_bytes.to_bytes()?);
1088        Ok(buffer)
1089    }
1090
1091    fn serialized_length(&self) -> usize {
1092        self.base_addr.serialized_length() + self.string_bytes.serialized_length()
1093    }
1094}
1095
1096impl FromBytes for NamedKeyAddr {
1097    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
1098        let (base_addr, remainder) = EntityAddr::from_bytes(bytes)?;
1099        let (string_bytes, remainder) = FromBytes::from_bytes(remainder)?;
1100        Ok((
1101            Self {
1102                base_addr,
1103                string_bytes,
1104            },
1105            remainder,
1106        ))
1107    }
1108}
1109
1110impl Display for NamedKeyAddr {
1111    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1112        write!(
1113            f,
1114            "{}{}-{}",
1115            NAMED_KEY_PREFIX,
1116            self.base_addr,
1117            base16::encode_lower(&self.string_bytes)
1118        )
1119    }
1120}
1121
1122impl Debug for NamedKeyAddr {
1123    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1124        write!(
1125            f,
1126            "NamedKeyAddr({:?}-{:?})",
1127            self.base_addr,
1128            base16::encode_lower(&self.string_bytes)
1129        )
1130    }
1131}
1132
1133#[cfg(any(feature = "testing", test))]
1134impl Distribution<NamedKeyAddr> for Standard {
1135    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> NamedKeyAddr {
1136        NamedKeyAddr {
1137            base_addr: rng.gen(),
1138            string_bytes: rng.gen(),
1139        }
1140    }
1141}
1142
1143/// A NamedKey value.
1144#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
1145#[cfg_attr(feature = "datasize", derive(DataSize))]
1146#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
1147pub struct NamedKeyValue {
1148    /// The actual `Key` encoded as a CLValue.
1149    named_key: CLValue,
1150    /// The name of the `Key` encoded as a CLValue.
1151    name: CLValue,
1152}
1153
1154impl NamedKeyValue {
1155    /// Constructs a new [`NamedKeyValue`].
1156    pub fn new(key: CLValue, name: CLValue) -> Self {
1157        Self {
1158            named_key: key,
1159            name,
1160        }
1161    }
1162
1163    /// Constructs a new [`NamedKeyValue`] from its [`Key`] and [`String`].
1164    pub fn from_concrete_values(named_key: Key, name: String) -> Result<Self, CLValueError> {
1165        let key_cl_value = CLValue::from_t(named_key)?;
1166        let string_cl_value = CLValue::from_t(name)?;
1167        Ok(Self::new(key_cl_value, string_cl_value))
1168    }
1169
1170    /// Returns the [`Key`] as a CLValue.
1171    pub fn get_key_as_cl_value(&self) -> &CLValue {
1172        &self.named_key
1173    }
1174
1175    /// Returns the [`String`] as a CLValue.
1176    pub fn get_name_as_cl_value(&self) -> &CLValue {
1177        &self.name
1178    }
1179
1180    /// Returns the concrete `Key` value
1181    pub fn get_key(&self) -> Result<Key, CLValueError> {
1182        self.named_key.clone().into_t::<Key>()
1183    }
1184
1185    /// Returns the concrete `String` value
1186    pub fn get_name(&self) -> Result<String, CLValueError> {
1187        self.name.clone().into_t::<String>()
1188    }
1189}
1190
1191impl ToBytes for NamedKeyValue {
1192    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
1193        let mut buffer = bytesrepr::allocate_buffer(self)?;
1194        buffer.append(&mut self.named_key.to_bytes()?);
1195        buffer.append(&mut self.name.to_bytes()?);
1196        Ok(buffer)
1197    }
1198
1199    fn serialized_length(&self) -> usize {
1200        self.named_key.serialized_length() + self.name.serialized_length()
1201    }
1202}
1203
1204impl FromBytes for NamedKeyValue {
1205    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
1206        let (named_key, remainder) = CLValue::from_bytes(bytes)?;
1207        let (name, remainder) = CLValue::from_bytes(remainder)?;
1208        Ok((Self { named_key, name }, remainder))
1209    }
1210}
1211
1212/// Collection of named message topics.
1213#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Default)]
1214#[cfg_attr(feature = "datasize", derive(DataSize))]
1215#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
1216#[serde(transparent, deny_unknown_fields)]
1217pub struct MessageTopics(
1218    #[serde(with = "BTreeMapToArray::<String, TopicNameHash, MessageTopicLabels>")]
1219    BTreeMap<String, TopicNameHash>,
1220);
1221
1222impl ToBytes for MessageTopics {
1223    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
1224        self.0.to_bytes()
1225    }
1226
1227    fn serialized_length(&self) -> usize {
1228        self.0.serialized_length()
1229    }
1230
1231    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
1232        self.0.write_bytes(writer)
1233    }
1234}
1235
1236impl FromBytes for MessageTopics {
1237    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
1238        let (message_topics_map, remainder) = BTreeMap::<String, TopicNameHash>::from_bytes(bytes)?;
1239        Ok((MessageTopics(message_topics_map), remainder))
1240    }
1241}
1242
1243impl MessageTopics {
1244    /// Adds new message topic by topic name.
1245    pub fn add_topic(
1246        &mut self,
1247        topic_name: &str,
1248        topic_name_hash: TopicNameHash,
1249    ) -> Result<(), MessageTopicError> {
1250        match self.0.entry(topic_name.to_string()) {
1251            Entry::Vacant(entry) => {
1252                entry.insert(topic_name_hash);
1253                Ok(())
1254            }
1255            Entry::Occupied(_) => Err(MessageTopicError::DuplicateTopic),
1256        }
1257    }
1258
1259    /// Checks if given topic name exists.
1260    pub fn has_topic(&self, topic_name: &str) -> bool {
1261        self.0.contains_key(topic_name)
1262    }
1263
1264    /// Gets the topic hash from the collection by its topic name.
1265    pub fn get(&self, topic_name: &str) -> Option<&TopicNameHash> {
1266        self.0.get(topic_name)
1267    }
1268
1269    /// Returns the length of the message topics.
1270    pub fn len(&self) -> usize {
1271        self.0.len()
1272    }
1273
1274    /// Returns true if no message topics are registered.
1275    pub fn is_empty(&self) -> bool {
1276        self.0.is_empty()
1277    }
1278
1279    /// Returns an iterator over the topic name and its hash.
1280    pub fn iter(&self) -> impl Iterator<Item = (&String, &TopicNameHash)> {
1281        self.0.iter()
1282    }
1283}
1284
1285struct MessageTopicLabels;
1286
1287impl KeyValueLabels for MessageTopicLabels {
1288    const KEY: &'static str = "topic_name";
1289    const VALUE: &'static str = "topic_name_hash";
1290}
1291
1292#[cfg(feature = "json-schema")]
1293impl KeyValueJsonSchema for MessageTopicLabels {
1294    const JSON_SCHEMA_KV_NAME: Option<&'static str> = Some("MessageTopic");
1295}
1296
1297impl From<BTreeMap<String, TopicNameHash>> for MessageTopics {
1298    fn from(topics: BTreeMap<String, TopicNameHash>) -> MessageTopics {
1299        MessageTopics(topics)
1300    }
1301}
1302
1303/// Errors that can occur while adding a new topic.
1304#[derive(PartialEq, Eq, Debug, Clone)]
1305#[non_exhaustive]
1306pub enum MessageTopicError {
1307    /// Topic already exists.
1308    DuplicateTopic,
1309    /// Maximum number of topics exceeded.
1310    MaxTopicsExceeded,
1311    /// Topic name size exceeded.
1312    TopicNameSizeExceeded,
1313}
1314
1315#[cfg(feature = "json-schema")]
1316static ADDRESSABLE_ENTITY: Lazy<AddressableEntity> = Lazy::new(|| {
1317    let secret_key = SecretKey::ed25519_from_bytes([0; 32]).unwrap();
1318    let account_hash = PublicKey::from(&secret_key).to_account_hash();
1319    let package_hash = PackageHash::new([0; 32]);
1320    let byte_code_hash = ByteCodeHash::new([0; 32]);
1321    let main_purse = URef::from_formatted_str(
1322        "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",
1323    )
1324    .unwrap();
1325    let weight = Weight::new(1);
1326    let associated_keys = AssociatedKeys::new(account_hash, weight);
1327    let action_thresholds = ActionThresholds::new(weight, weight, weight).unwrap();
1328    let protocol_version = ProtocolVersion::from_parts(2, 0, 0);
1329    AddressableEntity {
1330        protocol_version,
1331        entity_kind: EntityKind::Account(account_hash),
1332        package_hash,
1333        byte_code_hash,
1334        main_purse,
1335        associated_keys,
1336        action_thresholds,
1337    }
1338});
1339
1340/// The address for an AddressableEntity which contains the 32 bytes and tagging information.
1341pub type ContractAddress = PackageHash;
1342
1343/// Methods and type signatures supported by a contract.
1344#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1345#[cfg_attr(feature = "datasize", derive(DataSize))]
1346#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
1347pub struct AddressableEntity {
1348    protocol_version: ProtocolVersion,
1349    entity_kind: EntityKind,
1350    package_hash: PackageHash,
1351    byte_code_hash: ByteCodeHash,
1352    main_purse: URef,
1353
1354    associated_keys: AssociatedKeys,
1355    action_thresholds: ActionThresholds,
1356}
1357
1358impl From<AddressableEntity>
1359    for (
1360        PackageHash,
1361        ByteCodeHash,
1362        ProtocolVersion,
1363        URef,
1364        AssociatedKeys,
1365        ActionThresholds,
1366    )
1367{
1368    fn from(entity: AddressableEntity) -> Self {
1369        (
1370            entity.package_hash,
1371            entity.byte_code_hash,
1372            entity.protocol_version,
1373            entity.main_purse,
1374            entity.associated_keys,
1375            entity.action_thresholds,
1376        )
1377    }
1378}
1379
1380impl AddressableEntity {
1381    /// `AddressableEntity` constructor.
1382    #[allow(clippy::too_many_arguments)]
1383    pub fn new(
1384        package_hash: PackageHash,
1385        byte_code_hash: ByteCodeHash,
1386        protocol_version: ProtocolVersion,
1387        main_purse: URef,
1388        associated_keys: AssociatedKeys,
1389        action_thresholds: ActionThresholds,
1390        entity_kind: EntityKind,
1391    ) -> Self {
1392        AddressableEntity {
1393            package_hash,
1394            byte_code_hash,
1395            protocol_version,
1396            main_purse,
1397            action_thresholds,
1398            associated_keys,
1399            entity_kind,
1400        }
1401    }
1402
1403    /// Get the entity addr for this entity from the corresponding hash.
1404    pub fn entity_addr(&self, entity_hash: AddressableEntityHash) -> EntityAddr {
1405        let hash_addr = entity_hash.value();
1406        match self.entity_kind {
1407            EntityKind::System(_) => EntityAddr::new_system(hash_addr),
1408            EntityKind::Account(_) => EntityAddr::new_account(hash_addr),
1409            EntityKind::SmartContract(_) => EntityAddr::new_smart_contract(hash_addr),
1410        }
1411    }
1412
1413    pub fn entity_kind(&self) -> EntityKind {
1414        self.entity_kind
1415    }
1416
1417    /// Hash for accessing contract package
1418    pub fn package_hash(&self) -> PackageHash {
1419        self.package_hash
1420    }
1421
1422    /// Hash for accessing contract WASM
1423    pub fn byte_code_hash(&self) -> ByteCodeHash {
1424        self.byte_code_hash
1425    }
1426
1427    /// Get the protocol version this header is targeting.
1428    pub fn protocol_version(&self) -> ProtocolVersion {
1429        self.protocol_version
1430    }
1431
1432    /// Returns main purse.
1433    pub fn main_purse(&self) -> URef {
1434        self.main_purse
1435    }
1436
1437    /// Returns an [`AccessRights::ADD`]-only version of the main purse's [`URef`].
1438    pub fn main_purse_add_only(&self) -> URef {
1439        URef::new(self.main_purse.addr(), AccessRights::ADD)
1440    }
1441
1442    /// Returns associated keys.
1443    pub fn associated_keys(&self) -> &AssociatedKeys {
1444        &self.associated_keys
1445    }
1446
1447    /// Returns action thresholds.
1448    pub fn action_thresholds(&self) -> &ActionThresholds {
1449        &self.action_thresholds
1450    }
1451
1452    /// Adds an associated key to an addressable entity.
1453    pub fn add_associated_key(
1454        &mut self,
1455        account_hash: AccountHash,
1456        weight: Weight,
1457    ) -> Result<(), AddKeyFailure> {
1458        self.associated_keys.add_key(account_hash, weight)
1459    }
1460
1461    /// Checks if removing given key would properly satisfy thresholds.
1462    fn can_remove_key(&self, account_hash: AccountHash) -> bool {
1463        let total_weight_without = self
1464            .associated_keys
1465            .total_keys_weight_excluding(account_hash);
1466
1467        // Returns true if the total weight calculated without given public key would be greater or
1468        // equal to all of the thresholds.
1469        total_weight_without >= *self.action_thresholds().deployment()
1470            && total_weight_without >= *self.action_thresholds().key_management()
1471    }
1472
1473    /// Checks if adding a weight to a sum of all weights excluding the given key would make the
1474    /// resulting value to fall below any of the thresholds on account.
1475    fn can_update_key(&self, account_hash: AccountHash, weight: Weight) -> bool {
1476        // Calculates total weight of all keys excluding the given key
1477        let total_weight = self
1478            .associated_keys
1479            .total_keys_weight_excluding(account_hash);
1480
1481        // Safely calculate new weight by adding the updated weight
1482        let new_weight = total_weight.value().saturating_add(weight.value());
1483
1484        // Returns true if the new weight would be greater or equal to all of
1485        // the thresholds.
1486        new_weight >= self.action_thresholds().deployment().value()
1487            && new_weight >= self.action_thresholds().key_management().value()
1488    }
1489
1490    /// Removes an associated key from an addressable entity.
1491    ///
1492    /// Verifies that removing the key will not cause the remaining weight to fall below any action
1493    /// thresholds.
1494    pub fn remove_associated_key(
1495        &mut self,
1496        account_hash: AccountHash,
1497    ) -> Result<(), RemoveKeyFailure> {
1498        if self.associated_keys.contains_key(&account_hash) {
1499            // Check if removing this weight would fall below thresholds
1500            if !self.can_remove_key(account_hash) {
1501                return Err(RemoveKeyFailure::ThresholdViolation);
1502            }
1503        }
1504        self.associated_keys.remove_key(&account_hash)
1505    }
1506
1507    /// Updates an associated key.
1508    ///
1509    /// Returns an error if the update would result in a violation of the key management thresholds.
1510    pub fn update_associated_key(
1511        &mut self,
1512        account_hash: AccountHash,
1513        weight: Weight,
1514    ) -> Result<(), UpdateKeyFailure> {
1515        if let Some(current_weight) = self.associated_keys.get(&account_hash) {
1516            if weight < *current_weight {
1517                // New weight is smaller than current weight
1518                if !self.can_update_key(account_hash, weight) {
1519                    return Err(UpdateKeyFailure::ThresholdViolation);
1520                }
1521            }
1522        }
1523        self.associated_keys.update_key(account_hash, weight)
1524    }
1525
1526    /// Sets new action threshold for a given action type for the addressable entity.
1527    ///
1528    /// Returns an error if the new action threshold weight is greater than the total weight of the
1529    /// account's associated keys.
1530    pub fn set_action_threshold(
1531        &mut self,
1532        action_type: ActionType,
1533        weight: Weight,
1534    ) -> Result<(), SetThresholdFailure> {
1535        // Verify if new threshold weight exceeds total weight of all associated
1536        // keys.
1537        self.can_set_threshold(weight)?;
1538        // Set new weight for given action
1539        self.action_thresholds.set_threshold(action_type, weight)
1540    }
1541
1542    /// Sets a new action threshold for a given action type for the account without checking against
1543    /// the total weight of the associated keys.
1544    ///
1545    /// This should only be called when authorized by an administrator account.
1546    ///
1547    /// Returns an error if setting the action would cause the `ActionType::Deployment` threshold to
1548    /// be greater than any of the other action types.
1549    pub fn set_action_threshold_unchecked(
1550        &mut self,
1551        action_type: ActionType,
1552        threshold: Weight,
1553    ) -> Result<(), SetThresholdFailure> {
1554        self.action_thresholds.set_threshold(action_type, threshold)
1555    }
1556
1557    /// Verifies if user can set action threshold.
1558    pub fn can_set_threshold(&self, new_threshold: Weight) -> Result<(), SetThresholdFailure> {
1559        let total_weight = self.associated_keys.total_keys_weight();
1560        if new_threshold > total_weight {
1561            return Err(SetThresholdFailure::InsufficientTotalWeight);
1562        }
1563        Ok(())
1564    }
1565
1566    /// Checks whether all authorization keys are associated with this addressable entity.
1567    pub fn can_authorize(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
1568        !authorization_keys.is_empty()
1569            && authorization_keys
1570                .iter()
1571                .any(|e| self.associated_keys.contains_key(e))
1572    }
1573
1574    /// Checks whether the sum of the weights of all authorization keys is
1575    /// greater or equal to deploy threshold.
1576    pub fn can_deploy_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
1577        let total_weight = self
1578            .associated_keys
1579            .calculate_keys_weight(authorization_keys);
1580
1581        total_weight >= *self.action_thresholds().deployment()
1582    }
1583
1584    /// Checks whether the sum of the weights of all authorization keys is
1585    /// greater or equal to key management threshold.
1586    pub fn can_manage_keys_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
1587        let total_weight = self
1588            .associated_keys
1589            .calculate_keys_weight(authorization_keys);
1590
1591        total_weight >= *self.action_thresholds().key_management()
1592    }
1593
1594    /// Checks whether the sum of the weights of all authorization keys is
1595    /// greater or equal to upgrade management threshold.
1596    pub fn can_upgrade_with(&self, authorization_keys: &BTreeSet<AccountHash>) -> bool {
1597        let total_weight = self
1598            .associated_keys
1599            .calculate_keys_weight(authorization_keys);
1600
1601        total_weight >= *self.action_thresholds().upgrade_management()
1602    }
1603
1604    /// Addr for accessing wasm bytes
1605    pub fn byte_code_addr(&self) -> HashAddr {
1606        self.byte_code_hash.value()
1607    }
1608
1609    /// Set protocol_version.
1610    pub fn set_protocol_version(&mut self, protocol_version: ProtocolVersion) {
1611        self.protocol_version = protocol_version;
1612    }
1613
1614    /// Determines if `AddressableEntity` is compatible with a given `ProtocolVersion`.
1615    pub fn is_compatible_protocol_version(&self, protocol_version: ProtocolVersion) -> bool {
1616        let entity_protocol_version = self.protocol_version.value();
1617        let context_protocol_version = protocol_version.value();
1618        if entity_protocol_version.major == context_protocol_version.major {
1619            return true;
1620        }
1621        if entity_protocol_version.major == 1 && context_protocol_version.major == 2 {
1622            // the 1.x model has been deprecated but is still supported until 3.0.0
1623            return true;
1624        }
1625        false
1626    }
1627
1628    /// Returns the kind of `AddressableEntity`.
1629    pub fn kind(&self) -> EntityKind {
1630        self.entity_kind
1631    }
1632
1633    /// Is this an account?
1634    pub fn is_account_kind(&self) -> bool {
1635        matches!(self.entity_kind, EntityKind::Account(_))
1636    }
1637
1638    /// Key for the addressable entity
1639    pub fn entity_key(&self, entity_hash: AddressableEntityHash) -> Key {
1640        match self.entity_kind {
1641            EntityKind::System(_) => {
1642                Key::addressable_entity_key(EntityKindTag::System, entity_hash)
1643            }
1644            EntityKind::Account(_) => {
1645                Key::addressable_entity_key(EntityKindTag::Account, entity_hash)
1646            }
1647            EntityKind::SmartContract(_) => {
1648                Key::addressable_entity_key(EntityKindTag::SmartContract, entity_hash)
1649            }
1650        }
1651    }
1652
1653    /// Extracts the access rights from the named keys of the addressable entity.
1654    pub fn extract_access_rights(
1655        &self,
1656        entity_hash: AddressableEntityHash,
1657        named_keys: &NamedKeys,
1658    ) -> ContextAccessRights {
1659        let urefs_iter = named_keys
1660            .keys()
1661            .filter_map(|key| key.as_uref().copied())
1662            .chain(iter::once(self.main_purse));
1663        ContextAccessRights::new(entity_hash.value(), urefs_iter)
1664    }
1665
1666    // This method is not intended to be used by third party crates.
1667    #[doc(hidden)]
1668    #[cfg(feature = "json-schema")]
1669    pub fn example() -> &'static Self {
1670        &ADDRESSABLE_ENTITY
1671    }
1672}
1673
1674impl ToBytes for AddressableEntity {
1675    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
1676        let mut result = bytesrepr::allocate_buffer(self)?;
1677        self.package_hash().write_bytes(&mut result)?;
1678        self.byte_code_hash().write_bytes(&mut result)?;
1679        self.protocol_version().write_bytes(&mut result)?;
1680        self.main_purse().write_bytes(&mut result)?;
1681        self.associated_keys().write_bytes(&mut result)?;
1682        self.action_thresholds().write_bytes(&mut result)?;
1683        self.kind().write_bytes(&mut result)?;
1684        Ok(result)
1685    }
1686
1687    fn serialized_length(&self) -> usize {
1688        ToBytes::serialized_length(&self.package_hash)
1689            + ToBytes::serialized_length(&self.byte_code_hash)
1690            + ToBytes::serialized_length(&self.protocol_version)
1691            + ToBytes::serialized_length(&self.main_purse)
1692            + ToBytes::serialized_length(&self.associated_keys)
1693            + ToBytes::serialized_length(&self.action_thresholds)
1694            + ToBytes::serialized_length(&self.entity_kind)
1695    }
1696
1697    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
1698        self.package_hash().write_bytes(writer)?;
1699        self.byte_code_hash().write_bytes(writer)?;
1700        self.protocol_version().write_bytes(writer)?;
1701        self.main_purse().write_bytes(writer)?;
1702        self.associated_keys().write_bytes(writer)?;
1703        self.action_thresholds().write_bytes(writer)?;
1704        self.kind().write_bytes(writer)?;
1705        Ok(())
1706    }
1707}
1708
1709impl FromBytes for AddressableEntity {
1710    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
1711        let (package_hash, bytes) = PackageHash::from_bytes(bytes)?;
1712        let (byte_code_hash, bytes) = ByteCodeHash::from_bytes(bytes)?;
1713        let (protocol_version, bytes) = ProtocolVersion::from_bytes(bytes)?;
1714        let (main_purse, bytes) = URef::from_bytes(bytes)?;
1715        let (associated_keys, bytes) = AssociatedKeys::from_bytes(bytes)?;
1716        let (action_thresholds, bytes) = ActionThresholds::from_bytes(bytes)?;
1717        let (entity_kind, bytes) = EntityKind::from_bytes(bytes)?;
1718        Ok((
1719            AddressableEntity {
1720                package_hash,
1721                byte_code_hash,
1722                protocol_version,
1723                main_purse,
1724                associated_keys,
1725                action_thresholds,
1726                entity_kind,
1727            },
1728            bytes,
1729        ))
1730    }
1731}
1732
1733impl Default for AddressableEntity {
1734    fn default() -> Self {
1735        AddressableEntity {
1736            byte_code_hash: [0; KEY_HASH_LENGTH].into(),
1737            package_hash: [0; KEY_HASH_LENGTH].into(),
1738            protocol_version: ProtocolVersion::V1_0_0,
1739            main_purse: URef::default(),
1740            action_thresholds: ActionThresholds::default(),
1741            associated_keys: AssociatedKeys::default(),
1742            entity_kind: EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1),
1743        }
1744    }
1745}
1746
1747impl From<Contract> for AddressableEntity {
1748    fn from(value: Contract) -> Self {
1749        AddressableEntity::new(
1750            PackageHash::new(value.contract_package_hash().value()),
1751            ByteCodeHash::new(value.contract_wasm_hash().value()),
1752            value.protocol_version(),
1753            URef::default(),
1754            AssociatedKeys::default(),
1755            ActionThresholds::default(),
1756            EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1),
1757        )
1758    }
1759}
1760
1761impl From<Account> for AddressableEntity {
1762    fn from(value: Account) -> Self {
1763        AddressableEntity::new(
1764            PackageHash::default(),
1765            ByteCodeHash::new([0u8; 32]),
1766            ProtocolVersion::default(),
1767            value.main_purse(),
1768            value.associated_keys().clone().into(),
1769            value.action_thresholds().clone().into(),
1770            EntityKind::Account(value.account_hash()),
1771        )
1772    }
1773}
1774
1775#[cfg(test)]
1776mod tests {
1777    use super::*;
1778    use crate::{AccessRights, URef, UREF_ADDR_LENGTH};
1779
1780    #[cfg(feature = "json-schema")]
1781    use schemars::{gen::SchemaGenerator, schema::InstanceType};
1782
1783    #[test]
1784    fn entity_hash_from_slice() {
1785        let bytes: Vec<u8> = (0..32).collect();
1786        let entity_hash = HashAddr::try_from(&bytes[..]).expect("should create contract hash");
1787        let entity_hash = AddressableEntityHash::new(entity_hash);
1788        assert_eq!(&bytes, &entity_hash.as_bytes());
1789    }
1790
1791    #[test]
1792    fn entity_hash_from_str() {
1793        let entity_hash = AddressableEntityHash([3; 32]);
1794        let encoded = entity_hash.to_formatted_string();
1795        let decoded = AddressableEntityHash::from_formatted_str(&encoded).unwrap();
1796        assert_eq!(entity_hash, decoded);
1797
1798        let invalid_prefix =
1799            "addressable-entity--0000000000000000000000000000000000000000000000000000000000000000";
1800        assert!(AddressableEntityHash::from_formatted_str(invalid_prefix).is_err());
1801
1802        let short_addr =
1803            "addressable-entity-00000000000000000000000000000000000000000000000000000000000000";
1804        assert!(AddressableEntityHash::from_formatted_str(short_addr).is_err());
1805
1806        let long_addr =
1807            "addressable-entity-000000000000000000000000000000000000000000000000000000000000000000";
1808        assert!(AddressableEntityHash::from_formatted_str(long_addr).is_err());
1809
1810        let invalid_hex =
1811            "addressable-entity-000000000000000000000000000000000000000000000000000000000000000g";
1812        assert!(AddressableEntityHash::from_formatted_str(invalid_hex).is_err());
1813    }
1814
1815    #[test]
1816    fn named_key_addr_from_str() {
1817        let named_key_addr =
1818            NamedKeyAddr::new_named_key_entry(EntityAddr::new_smart_contract([3; 32]), [4; 32]);
1819        let encoded = named_key_addr.to_formatted_string();
1820        let decoded = NamedKeyAddr::from_formatted_str(&encoded).unwrap();
1821        assert_eq!(named_key_addr, decoded);
1822    }
1823
1824    #[test]
1825    fn entity_hash_serde_roundtrip() {
1826        let entity_hash = AddressableEntityHash([255; 32]);
1827        let serialized = bincode::serialize(&entity_hash).unwrap();
1828        let deserialized = bincode::deserialize(&serialized).unwrap();
1829        assert_eq!(entity_hash, deserialized)
1830    }
1831
1832    #[test]
1833    fn entity_hash_json_roundtrip() {
1834        let entity_hash = AddressableEntityHash([255; 32]);
1835        let json_string = serde_json::to_string_pretty(&entity_hash).unwrap();
1836        let decoded = serde_json::from_str(&json_string).unwrap();
1837        assert_eq!(entity_hash, decoded)
1838    }
1839
1840    #[test]
1841    fn entity_addr_formatted_string_roundtrip() {
1842        let entity_addr = EntityAddr::Account([5; 32]);
1843        let encoded = entity_addr.to_formatted_string();
1844        let decoded = EntityAddr::from_formatted_str(&encoded).expect("must get entity addr");
1845        assert_eq!(decoded, entity_addr);
1846
1847        let entity_addr = EntityAddr::SmartContract([5; 32]);
1848        let encoded = entity_addr.to_formatted_string();
1849        let decoded = EntityAddr::from_formatted_str(&encoded).expect("must get entity addr");
1850        assert_eq!(decoded, entity_addr);
1851
1852        let entity_addr = EntityAddr::System([5; 32]);
1853        let encoded = entity_addr.to_formatted_string();
1854        let decoded = EntityAddr::from_formatted_str(&encoded).expect("must get entity addr");
1855        assert_eq!(decoded, entity_addr);
1856    }
1857
1858    #[test]
1859    fn entity_addr_serialization_roundtrip() {
1860        for addr in [
1861            EntityAddr::new_system([1; 32]),
1862            EntityAddr::new_account([1; 32]),
1863            EntityAddr::new_smart_contract([1; 32]),
1864        ] {
1865            bytesrepr::test_serialization_roundtrip(&addr);
1866        }
1867    }
1868
1869    #[test]
1870    fn entity_addr_serde_roundtrip() {
1871        for addr in [
1872            EntityAddr::new_system([1; 32]),
1873            EntityAddr::new_account([1; 32]),
1874            EntityAddr::new_smart_contract([1; 32]),
1875        ] {
1876            let serialized = bincode::serialize(&addr).unwrap();
1877            let deserialized = bincode::deserialize(&serialized).unwrap();
1878            assert_eq!(addr, deserialized)
1879        }
1880    }
1881
1882    #[test]
1883    fn entity_addr_json_roundtrip() {
1884        for addr in [
1885            EntityAddr::new_system([1; 32]),
1886            EntityAddr::new_account([1; 32]),
1887            EntityAddr::new_smart_contract([1; 32]),
1888        ] {
1889            let json_string = serde_json::to_string_pretty(&addr).unwrap();
1890            let decoded = serde_json::from_str(&json_string).unwrap();
1891            assert_eq!(addr, decoded)
1892        }
1893    }
1894
1895    #[cfg(feature = "json-schema")]
1896    #[test]
1897    fn entity_addr_schema() {
1898        let mut gen = SchemaGenerator::default();
1899        let any_of = EntityAddr::json_schema(&mut gen)
1900            .into_object()
1901            .subschemas
1902            .expect("should have subschemas")
1903            .any_of
1904            .expect("should have any_of");
1905        for elem in any_of {
1906            let schema = elem
1907                .into_object()
1908                .instance_type
1909                .expect("should have instance type");
1910            assert!(schema.contains(&InstanceType::String), "{:?}", schema);
1911        }
1912    }
1913
1914    #[test]
1915    fn should_extract_access_rights() {
1916        const MAIN_PURSE: URef = URef::new([2; 32], AccessRights::READ_ADD_WRITE);
1917
1918        let entity_hash = AddressableEntityHash([255; 32]);
1919        let uref = URef::new([84; UREF_ADDR_LENGTH], AccessRights::READ_ADD);
1920        let uref_r = URef::new([42; UREF_ADDR_LENGTH], AccessRights::READ);
1921        let uref_a = URef::new([42; UREF_ADDR_LENGTH], AccessRights::ADD);
1922        let uref_w = URef::new([42; UREF_ADDR_LENGTH], AccessRights::WRITE);
1923        let mut named_keys = NamedKeys::new();
1924        named_keys.insert("a".to_string(), Key::URef(uref_r));
1925        named_keys.insert("b".to_string(), Key::URef(uref_a));
1926        named_keys.insert("c".to_string(), Key::URef(uref_w));
1927        named_keys.insert("d".to_string(), Key::URef(uref));
1928        let associated_keys = AssociatedKeys::new(AccountHash::new([254; 32]), Weight::new(1));
1929        let contract = AddressableEntity::new(
1930            PackageHash::new([254; 32]),
1931            ByteCodeHash::new([253; 32]),
1932            ProtocolVersion::V1_0_0,
1933            MAIN_PURSE,
1934            associated_keys,
1935            ActionThresholds::new(Weight::new(1), Weight::new(1), Weight::new(1))
1936                .expect("should create thresholds"),
1937            EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1),
1938        );
1939        let access_rights = contract.extract_access_rights(entity_hash, &named_keys);
1940        let expected_uref = URef::new([42; UREF_ADDR_LENGTH], AccessRights::READ_ADD_WRITE);
1941        assert!(
1942            access_rights.has_access_rights_to_uref(&uref),
1943            "urefs in named keys should be included in access rights"
1944        );
1945        assert!(
1946            access_rights.has_access_rights_to_uref(&expected_uref),
1947            "multiple access right bits to the same uref should coalesce"
1948        );
1949    }
1950}
1951
1952#[cfg(test)]
1953mod prop_tests {
1954    use proptest::prelude::*;
1955
1956    use crate::{bytesrepr, gens};
1957
1958    proptest! {
1959        #[test]
1960        fn test_value_contract(contract in gens::addressable_entity_arb()) {
1961            bytesrepr::test_serialization_roundtrip(&contract);
1962        }
1963    }
1964}