casper_types/
key.rs

1//! Key types.
2
3use alloc::{
4    format,
5    string::{String, ToString},
6    vec::Vec,
7};
8
9use core::{
10    convert::TryFrom,
11    fmt::{self, Debug, Display, Formatter},
12    str::FromStr,
13};
14
15use blake2::{
16    digest::{Update, VariableOutput},
17    VarBlake2b,
18};
19#[cfg(feature = "datasize")]
20use datasize::DataSize;
21use rand::{
22    distributions::{Distribution, Standard},
23    Rng,
24};
25use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
26
27use crate::{
28    account::{self, AccountHash, ACCOUNT_HASH_LENGTH},
29    bytesrepr::{self, Error, FromBytes, ToBytes, U64_SERIALIZED_LENGTH},
30    checksummed_hex,
31    contract_wasm::ContractWasmHash,
32    contracts::{ContractHash, ContractPackageHash},
33    uref::{self, URef, URefAddr, UREF_SERIALIZED_LENGTH},
34    DeployHash, EraId, Tagged, TransferAddr, TransferFromStrError, DEPLOY_HASH_LENGTH,
35    TRANSFER_ADDR_LENGTH, UREF_ADDR_LENGTH,
36};
37
38const HASH_PREFIX: &str = "hash-";
39const DEPLOY_INFO_PREFIX: &str = "deploy-";
40const ERA_INFO_PREFIX: &str = "era-";
41const BALANCE_PREFIX: &str = "balance-";
42const BID_PREFIX: &str = "bid-";
43const WITHDRAW_PREFIX: &str = "withdraw-";
44const DICTIONARY_PREFIX: &str = "dictionary-";
45const UNBOND_PREFIX: &str = "unbond-";
46const SYSTEM_CONTRACT_REGISTRY_PREFIX: &str = "system-contract-registry-";
47const ERA_SUMMARY_PREFIX: &str = "era-summary-";
48const CHAINSPEC_REGISTRY_PREFIX: &str = "chainspec-registry-";
49const CHECKSUM_REGISTRY_PREFIX: &str = "checksum-registry-";
50
51/// The number of bytes in a Blake2b hash
52pub const BLAKE2B_DIGEST_LENGTH: usize = 32;
53/// The number of bytes in a [`Key::Hash`].
54pub const KEY_HASH_LENGTH: usize = 32;
55/// The number of bytes in a [`Key::Transfer`].
56pub const KEY_TRANSFER_LENGTH: usize = TRANSFER_ADDR_LENGTH;
57/// The number of bytes in a [`Key::DeployInfo`].
58pub const KEY_DEPLOY_INFO_LENGTH: usize = DEPLOY_HASH_LENGTH;
59/// The number of bytes in a [`Key::Dictionary`].
60pub const KEY_DICTIONARY_LENGTH: usize = 32;
61/// The maximum length for a `dictionary_item_key`.
62pub const DICTIONARY_ITEM_KEY_MAX_LENGTH: usize = 128;
63const PADDING_BYTES: [u8; 32] = [0u8; 32];
64const KEY_ID_SERIALIZED_LENGTH: usize = 1;
65// u8 used to determine the ID
66const KEY_HASH_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_HASH_LENGTH;
67const KEY_UREF_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + UREF_SERIALIZED_LENGTH;
68const KEY_TRANSFER_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_TRANSFER_LENGTH;
69const KEY_DEPLOY_INFO_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_DEPLOY_INFO_LENGTH;
70const KEY_ERA_INFO_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + U64_SERIALIZED_LENGTH;
71const KEY_BALANCE_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + UREF_ADDR_LENGTH;
72const KEY_BID_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_HASH_LENGTH;
73const KEY_WITHDRAW_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_HASH_LENGTH;
74const KEY_UNBOND_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_HASH_LENGTH;
75const KEY_DICTIONARY_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + KEY_DICTIONARY_LENGTH;
76const KEY_SYSTEM_CONTRACT_REGISTRY_SERIALIZED_LENGTH: usize =
77    KEY_ID_SERIALIZED_LENGTH + PADDING_BYTES.len();
78const KEY_ERA_SUMMARY_SERIALIZED_LENGTH: usize = KEY_ID_SERIALIZED_LENGTH + PADDING_BYTES.len();
79const KEY_CHAINSPEC_REGISTRY_SERIALIZED_LENGTH: usize =
80    KEY_ID_SERIALIZED_LENGTH + PADDING_BYTES.len();
81const KEY_CHECKSUM_REGISTRY_SERIALIZED_LENGTH: usize =
82    KEY_ID_SERIALIZED_LENGTH + PADDING_BYTES.len();
83
84/// An alias for [`Key`]s hash variant.
85pub type HashAddr = [u8; KEY_HASH_LENGTH];
86
87/// An alias for [`Key`]s dictionary variant.
88pub type DictionaryAddr = [u8; KEY_DICTIONARY_LENGTH];
89
90#[allow(missing_docs)]
91#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
92#[repr(u8)]
93pub enum KeyTag {
94    Account = 0,
95    Hash = 1,
96    URef = 2,
97    Transfer = 3,
98    DeployInfo = 4,
99    EraInfo = 5,
100    Balance = 6,
101    Bid = 7,
102    Withdraw = 8,
103    Dictionary = 9,
104    SystemContractRegistry = 10,
105    EraSummary = 11,
106    Unbond = 12,
107    ChainspecRegistry = 13,
108    ChecksumRegistry = 14,
109}
110
111/// The type under which data (e.g. [`CLValue`](crate::CLValue)s, smart contracts, user accounts)
112/// are indexed on the network.
113#[repr(C)]
114#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
115#[cfg_attr(feature = "datasize", derive(DataSize))]
116pub enum Key {
117    /// A `Key` under which a user account is stored.
118    Account(AccountHash),
119    /// A `Key` under which a smart contract is stored and which is the pseudo-hash of the
120    /// contract.
121    Hash(HashAddr),
122    /// A `Key` which is a [`URef`], under which most types of data can be stored.
123    URef(URef),
124    /// A `Key` under which we store a transfer.
125    Transfer(TransferAddr),
126    /// A `Key` under which we store a deploy info.
127    DeployInfo(DeployHash),
128    /// A `Key` under which we store an era info.
129    EraInfo(EraId),
130    /// A `Key` under which we store a purse balance.
131    Balance(URefAddr),
132    /// A `Key` under which we store bid information
133    Bid(AccountHash),
134    /// A `Key` under which we store withdraw information.
135    Withdraw(AccountHash),
136    /// A `Key` variant whose value is derived by hashing [`URef`]s address and arbitrary data.
137    Dictionary(DictionaryAddr),
138    /// A `Key` variant under which system contract hashes are stored.
139    SystemContractRegistry,
140    /// A `Key` under which we store current era info.
141    EraSummary,
142    /// A `Key` under which we store unbond information.
143    Unbond(AccountHash),
144    /// A `Key` variant under which chainspec and other hashes are stored.
145    ChainspecRegistry,
146    /// A `Key` variant under which we store a registry of checksums.
147    ChecksumRegistry,
148}
149
150/// Errors produced when converting a `String` into a `Key`.
151#[derive(Debug)]
152#[non_exhaustive]
153pub enum FromStrError {
154    /// Account parse error.
155    Account(account::FromStrError),
156    /// Hash parse error.
157    Hash(String),
158    /// URef parse error.
159    URef(uref::FromStrError),
160    /// Transfer parse error.
161    Transfer(TransferFromStrError),
162    /// DeployInfo parse error.
163    DeployInfo(String),
164    /// EraInfo parse error.
165    EraInfo(String),
166    /// Balance parse error.
167    Balance(String),
168    /// Bid parse error.
169    Bid(String),
170    /// Withdraw parse error.
171    Withdraw(String),
172    /// Dictionary parse error.
173    Dictionary(String),
174    /// System contract registry parse error.
175    SystemContractRegistry(String),
176    /// Era summary parse error.
177    EraSummary(String),
178    /// Unbond parse error.
179    Unbond(String),
180    /// Chainspec registry error.
181    ChainspecRegistry(String),
182    /// Checksum registry error.
183    ChecksumRegistry(String),
184    /// Unknown prefix.
185    UnknownPrefix,
186}
187
188impl From<account::FromStrError> for FromStrError {
189    fn from(error: account::FromStrError) -> Self {
190        FromStrError::Account(error)
191    }
192}
193
194impl From<TransferFromStrError> for FromStrError {
195    fn from(error: TransferFromStrError) -> Self {
196        FromStrError::Transfer(error)
197    }
198}
199
200impl From<uref::FromStrError> for FromStrError {
201    fn from(error: uref::FromStrError) -> Self {
202        FromStrError::URef(error)
203    }
204}
205
206impl Display for FromStrError {
207    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
208        match self {
209            FromStrError::Account(error) => write!(f, "account-key from string error: {}", error),
210            FromStrError::Hash(error) => write!(f, "hash-key from string error: {}", error),
211            FromStrError::URef(error) => write!(f, "uref-key from string error: {}", error),
212            FromStrError::Transfer(error) => write!(f, "transfer-key from string error: {}", error),
213            FromStrError::DeployInfo(error) => {
214                write!(f, "deploy-info-key from string error: {}", error)
215            }
216            FromStrError::EraInfo(error) => write!(f, "era-info-key from string error: {}", error),
217            FromStrError::Balance(error) => write!(f, "balance-key from string error: {}", error),
218            FromStrError::Bid(error) => write!(f, "bid-key from string error: {}", error),
219            FromStrError::Withdraw(error) => write!(f, "withdraw-key from string error: {}", error),
220            FromStrError::Dictionary(error) => {
221                write!(f, "dictionary-key from string error: {}", error)
222            }
223            FromStrError::SystemContractRegistry(error) => {
224                write!(
225                    f,
226                    "system-contract-registry-key from string error: {}",
227                    error
228                )
229            }
230            FromStrError::EraSummary(error) => {
231                write!(f, "era-summary-key from string error: {}", error)
232            }
233            FromStrError::Unbond(error) => {
234                write!(f, "unbond-key from string error: {}", error)
235            }
236            FromStrError::ChainspecRegistry(error) => {
237                write!(f, "chainspec-registry-key from string error: {}", error)
238            }
239            FromStrError::ChecksumRegistry(error) => {
240                write!(f, "checksum-registry-key from string error: {}", error)
241            }
242            FromStrError::UnknownPrefix => write!(f, "unknown prefix for key"),
243        }
244    }
245}
246
247impl Key {
248    // This method is not intended to be used by third party crates.
249    #[doc(hidden)]
250    pub fn type_string(&self) -> String {
251        match self {
252            Key::Account(_) => String::from("Key::Account"),
253            Key::Hash(_) => String::from("Key::Hash"),
254            Key::URef(_) => String::from("Key::URef"),
255            Key::Transfer(_) => String::from("Key::Transfer"),
256            Key::DeployInfo(_) => String::from("Key::DeployInfo"),
257            Key::EraInfo(_) => String::from("Key::EraInfo"),
258            Key::Balance(_) => String::from("Key::Balance"),
259            Key::Bid(_) => String::from("Key::Bid"),
260            Key::Withdraw(_) => String::from("Key::Unbond"),
261            Key::Dictionary(_) => String::from("Key::Dictionary"),
262            Key::SystemContractRegistry => String::from("Key::SystemContractRegistry"),
263            Key::EraSummary => String::from("Key::EraSummary"),
264            Key::Unbond(_) => String::from("Key::Unbond"),
265            Key::ChainspecRegistry => String::from("Key::ChainspecRegistry"),
266            Key::ChecksumRegistry => String::from("Key::ChecksumRegistry"),
267        }
268    }
269
270    /// Returns the maximum size a [`Key`] can be serialized into.
271    pub const fn max_serialized_length() -> usize {
272        KEY_UREF_SERIALIZED_LENGTH
273    }
274
275    /// If `self` is of type [`Key::URef`], returns `self` with the
276    /// [`AccessRights`](crate::AccessRights) stripped from the wrapped [`URef`], otherwise
277    /// returns `self` unmodified.
278    #[must_use]
279    pub fn normalize(self) -> Key {
280        match self {
281            Key::URef(uref) => Key::URef(uref.remove_access_rights()),
282            other => other,
283        }
284    }
285
286    /// Returns a human-readable version of `self`, with the inner bytes encoded to Base16.
287    pub fn to_formatted_string(self) -> String {
288        match self {
289            Key::Account(account_hash) => account_hash.to_formatted_string(),
290            Key::Hash(addr) => format!("{}{}", HASH_PREFIX, base16::encode_lower(&addr)),
291            Key::URef(uref) => uref.to_formatted_string(),
292            Key::Transfer(transfer_addr) => transfer_addr.to_formatted_string(),
293            Key::DeployInfo(addr) => {
294                format!(
295                    "{}{}",
296                    DEPLOY_INFO_PREFIX,
297                    base16::encode_lower(addr.as_bytes())
298                )
299            }
300            Key::EraInfo(era_id) => {
301                format!("{}{}", ERA_INFO_PREFIX, era_id.value())
302            }
303            Key::Balance(uref_addr) => {
304                format!("{}{}", BALANCE_PREFIX, base16::encode_lower(&uref_addr))
305            }
306            Key::Bid(account_hash) => {
307                format!("{}{}", BID_PREFIX, base16::encode_lower(&account_hash))
308            }
309            Key::Withdraw(account_hash) => {
310                format!("{}{}", WITHDRAW_PREFIX, base16::encode_lower(&account_hash))
311            }
312            Key::Dictionary(dictionary_addr) => {
313                format!(
314                    "{}{}",
315                    DICTIONARY_PREFIX,
316                    base16::encode_lower(&dictionary_addr)
317                )
318            }
319            Key::SystemContractRegistry => {
320                format!(
321                    "{}{}",
322                    SYSTEM_CONTRACT_REGISTRY_PREFIX,
323                    base16::encode_lower(&PADDING_BYTES)
324                )
325            }
326            Key::EraSummary => {
327                format!(
328                    "{}{}",
329                    ERA_SUMMARY_PREFIX,
330                    base16::encode_lower(&PADDING_BYTES)
331                )
332            }
333            Key::Unbond(account_hash) => {
334                format!("{}{}", UNBOND_PREFIX, base16::encode_lower(&account_hash))
335            }
336            Key::ChainspecRegistry => {
337                format!(
338                    "{}{}",
339                    CHAINSPEC_REGISTRY_PREFIX,
340                    base16::encode_lower(&PADDING_BYTES)
341                )
342            }
343            Key::ChecksumRegistry => {
344                format!(
345                    "{}{}",
346                    CHECKSUM_REGISTRY_PREFIX,
347                    base16::encode_lower(&PADDING_BYTES)
348                )
349            }
350        }
351    }
352
353    /// Parses a string formatted as per `Self::to_formatted_string()` into a `Key`.
354    pub fn from_formatted_str(input: &str) -> Result<Key, FromStrError> {
355        match AccountHash::from_formatted_str(input) {
356            Ok(account_hash) => return Ok(Key::Account(account_hash)),
357            Err(account::FromStrError::InvalidPrefix) => {}
358            Err(error) => return Err(error.into()),
359        }
360
361        if let Some(hex) = input.strip_prefix(HASH_PREFIX) {
362            let addr = checksummed_hex::decode(hex)
363                .map_err(|error| FromStrError::Hash(error.to_string()))?;
364            let hash_addr = HashAddr::try_from(addr.as_ref())
365                .map_err(|error| FromStrError::Hash(error.to_string()))?;
366            return Ok(Key::Hash(hash_addr));
367        }
368
369        if let Some(hex) = input.strip_prefix(DEPLOY_INFO_PREFIX) {
370            let hash = checksummed_hex::decode(hex)
371                .map_err(|error| FromStrError::DeployInfo(error.to_string()))?;
372            let hash_array = <[u8; DEPLOY_HASH_LENGTH]>::try_from(hash.as_ref())
373                .map_err(|error| FromStrError::DeployInfo(error.to_string()))?;
374            return Ok(Key::DeployInfo(DeployHash::new(hash_array)));
375        }
376
377        match TransferAddr::from_formatted_str(input) {
378            Ok(transfer_addr) => return Ok(Key::Transfer(transfer_addr)),
379            Err(TransferFromStrError::InvalidPrefix) => {}
380            Err(error) => return Err(error.into()),
381        }
382
383        match URef::from_formatted_str(input) {
384            Ok(uref) => return Ok(Key::URef(uref)),
385            Err(uref::FromStrError::InvalidPrefix) => {}
386            Err(error) => return Err(error.into()),
387        }
388
389        if let Some(era_summary_padding) = input.strip_prefix(ERA_SUMMARY_PREFIX) {
390            let padded_bytes = checksummed_hex::decode(era_summary_padding)
391                .map_err(|error| FromStrError::EraSummary(error.to_string()))?;
392            let _padding: [u8; 32] = TryFrom::try_from(padded_bytes.as_ref()).map_err(|_| {
393                FromStrError::EraSummary("Failed to deserialize era summary key".to_string())
394            })?;
395            return Ok(Key::EraSummary);
396        }
397
398        if let Some(era_id_str) = input.strip_prefix(ERA_INFO_PREFIX) {
399            let era_id = EraId::from_str(era_id_str)
400                .map_err(|error| FromStrError::EraInfo(error.to_string()))?;
401            return Ok(Key::EraInfo(era_id));
402        }
403
404        if let Some(hex) = input.strip_prefix(BALANCE_PREFIX) {
405            let addr = checksummed_hex::decode(hex)
406                .map_err(|error| FromStrError::Balance(error.to_string()))?;
407            let uref_addr = URefAddr::try_from(addr.as_ref())
408                .map_err(|error| FromStrError::Balance(error.to_string()))?;
409            return Ok(Key::Balance(uref_addr));
410        }
411
412        if let Some(hex) = input.strip_prefix(BID_PREFIX) {
413            let hash = checksummed_hex::decode(hex)
414                .map_err(|error| FromStrError::Bid(error.to_string()))?;
415            let account_hash = <[u8; ACCOUNT_HASH_LENGTH]>::try_from(hash.as_ref())
416                .map_err(|error| FromStrError::Bid(error.to_string()))?;
417            return Ok(Key::Bid(AccountHash::new(account_hash)));
418        }
419
420        if let Some(hex) = input.strip_prefix(WITHDRAW_PREFIX) {
421            let hash = checksummed_hex::decode(hex)
422                .map_err(|error| FromStrError::Withdraw(error.to_string()))?;
423            let account_hash = <[u8; ACCOUNT_HASH_LENGTH]>::try_from(hash.as_ref())
424                .map_err(|error| FromStrError::Withdraw(error.to_string()))?;
425            return Ok(Key::Withdraw(AccountHash::new(account_hash)));
426        }
427
428        if let Some(hex) = input.strip_prefix(UNBOND_PREFIX) {
429            let hash = checksummed_hex::decode(hex)
430                .map_err(|error| FromStrError::Unbond(error.to_string()))?;
431            let account_hash = <[u8; ACCOUNT_HASH_LENGTH]>::try_from(hash.as_ref())
432                .map_err(|error| FromStrError::Unbond(error.to_string()))?;
433            return Ok(Key::Unbond(AccountHash::new(account_hash)));
434        }
435
436        if let Some(dictionary_addr) = input.strip_prefix(DICTIONARY_PREFIX) {
437            let dictionary_addr_bytes = checksummed_hex::decode(dictionary_addr)
438                .map_err(|error| FromStrError::Dictionary(error.to_string()))?;
439            let addr = DictionaryAddr::try_from(dictionary_addr_bytes.as_ref())
440                .map_err(|error| FromStrError::Dictionary(error.to_string()))?;
441            return Ok(Key::Dictionary(addr));
442        }
443
444        if let Some(registry_address) = input.strip_prefix(SYSTEM_CONTRACT_REGISTRY_PREFIX) {
445            let padded_bytes = checksummed_hex::decode(registry_address)
446                .map_err(|error| FromStrError::SystemContractRegistry(error.to_string()))?;
447            let _padding: [u8; 32] = TryFrom::try_from(padded_bytes.as_ref()).map_err(|_| {
448                FromStrError::SystemContractRegistry(
449                    "Failed to deserialize system registry key".to_string(),
450                )
451            })?;
452            return Ok(Key::SystemContractRegistry);
453        }
454
455        if let Some(registry_address) = input.strip_prefix(CHAINSPEC_REGISTRY_PREFIX) {
456            let padded_bytes = checksummed_hex::decode(registry_address)
457                .map_err(|error| FromStrError::ChainspecRegistry(error.to_string()))?;
458            let _padding: [u8; 32] = TryFrom::try_from(padded_bytes.as_ref()).map_err(|_| {
459                FromStrError::ChainspecRegistry(
460                    "Failed to deserialize chainspec registry key".to_string(),
461                )
462            })?;
463            return Ok(Key::ChainspecRegistry);
464        }
465
466        if let Some(registry_address) = input.strip_prefix(CHECKSUM_REGISTRY_PREFIX) {
467            let padded_bytes = checksummed_hex::decode(registry_address)
468                .map_err(|error| FromStrError::ChecksumRegistry(error.to_string()))?;
469            let _padding: [u8; 32] = TryFrom::try_from(padded_bytes.as_ref()).map_err(|_| {
470                FromStrError::ChecksumRegistry(
471                    "Failed to deserialize checksum registry key".to_string(),
472                )
473            })?;
474            return Ok(Key::ChecksumRegistry);
475        }
476
477        Err(FromStrError::UnknownPrefix)
478    }
479
480    /// Returns the inner bytes of `self` if `self` is of type [`Key::Account`], otherwise returns
481    /// `None`.
482    pub fn into_account(self) -> Option<AccountHash> {
483        match self {
484            Key::Account(bytes) => Some(bytes),
485            _ => None,
486        }
487    }
488
489    /// Returns the inner bytes of `self` if `self` is of type [`Key::Hash`], otherwise returns
490    /// `None`.
491    pub fn into_hash(self) -> Option<HashAddr> {
492        match self {
493            Key::Hash(hash) => Some(hash),
494            _ => None,
495        }
496    }
497
498    /// Returns a reference to the inner [`URef`] if `self` is of type [`Key::URef`], otherwise
499    /// returns `None`.
500    pub fn as_uref(&self) -> Option<&URef> {
501        match self {
502            Key::URef(uref) => Some(uref),
503            _ => None,
504        }
505    }
506
507    /// Returns a reference to the inner [`URef`] if `self` is of type [`Key::URef`], otherwise
508    /// returns `None`.
509    pub fn as_uref_mut(&mut self) -> Option<&mut URef> {
510        match self {
511            Key::URef(uref) => Some(uref),
512            _ => None,
513        }
514    }
515
516    /// Returns a reference to the inner `URefAddr` if `self` is of type [`Key::Balance`],
517    /// otherwise returns `None`.
518    pub fn as_balance(&self) -> Option<&URefAddr> {
519        if let Self::Balance(v) = self {
520            Some(v)
521        } else {
522            None
523        }
524    }
525
526    /// Returns the inner [`URef`] if `self` is of type [`Key::URef`], otherwise returns `None`.
527    pub fn into_uref(self) -> Option<URef> {
528        match self {
529            Key::URef(uref) => Some(uref),
530            _ => None,
531        }
532    }
533
534    /// Returns a reference to the inner [`DictionaryAddr`] if `self` is of type
535    /// [`Key::Dictionary`], otherwise returns `None`.
536    pub fn as_dictionary(&self) -> Option<&DictionaryAddr> {
537        match self {
538            Key::Dictionary(v) => Some(v),
539            _ => None,
540        }
541    }
542
543    /// Casts a [`Key::URef`] to a [`Key::Hash`]
544    pub fn uref_to_hash(&self) -> Option<Key> {
545        let uref = self.as_uref()?;
546        let addr = uref.addr();
547        Some(Key::Hash(addr))
548    }
549
550    /// Casts a [`Key::Withdraw`] to a [`Key::Unbond`]
551    pub fn withdraw_to_unbond(&self) -> Option<Key> {
552        if let Key::Withdraw(account_hash) = self {
553            return Some(Key::Unbond(*account_hash));
554        }
555        None
556    }
557
558    /// Creates a new [`Key::Dictionary`] variant based on a `seed_uref` and a `dictionary_item_key`
559    /// bytes.
560    pub fn dictionary(seed_uref: URef, dictionary_item_key: &[u8]) -> Key {
561        // NOTE: Expect below is safe because the length passed is supported.
562        let mut hasher = VarBlake2b::new(BLAKE2B_DIGEST_LENGTH).expect("should create hasher");
563        hasher.update(seed_uref.addr().as_ref());
564        hasher.update(dictionary_item_key);
565        // NOTE: Assumed safe as size of `HashAddr` equals to the output provided by hasher.
566        let mut addr = HashAddr::default();
567        hasher.finalize_variable(|hash| addr.clone_from_slice(hash));
568        Key::Dictionary(addr)
569    }
570
571    /// Returns true if the key is of type [`Key::Dictionary`].
572    pub fn is_dictionary_key(&self) -> bool {
573        if let Key::Dictionary(_) = self {
574            return true;
575        }
576        false
577    }
578
579    /// Returns true if the key is of type [`Key::Account`].
580    pub fn as_account(&self) -> Option<&AccountHash> {
581        if let Self::Account(v) = self {
582            Some(v)
583        } else {
584            None
585        }
586    }
587}
588
589impl Display for Key {
590    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
591        match self {
592            Key::Account(account_hash) => write!(f, "Key::Account({})", account_hash),
593            Key::Hash(addr) => write!(f, "Key::Hash({})", base16::encode_lower(&addr)),
594            Key::URef(uref) => write!(f, "Key::{}", uref), /* Display impl for URef will append */
595            Key::Transfer(transfer_addr) => write!(f, "Key::Transfer({})", transfer_addr),
596            Key::DeployInfo(addr) => write!(
597                f,
598                "Key::DeployInfo({})",
599                base16::encode_lower(addr.as_bytes())
600            ),
601            Key::EraInfo(era_id) => write!(f, "Key::EraInfo({})", era_id),
602            Key::Balance(uref_addr) => {
603                write!(f, "Key::Balance({})", base16::encode_lower(uref_addr))
604            }
605            Key::Bid(account_hash) => write!(f, "Key::Bid({})", account_hash),
606            Key::Withdraw(account_hash) => write!(f, "Key::Withdraw({})", account_hash),
607            Key::Dictionary(addr) => {
608                write!(f, "Key::Dictionary({})", base16::encode_lower(addr))
609            }
610            Key::SystemContractRegistry => write!(
611                f,
612                "Key::SystemContractRegistry({})",
613                base16::encode_lower(&PADDING_BYTES)
614            ),
615            Key::EraSummary => write!(
616                f,
617                "Key::EraSummary({})",
618                base16::encode_lower(&PADDING_BYTES),
619            ),
620            Key::Unbond(account_hash) => write!(f, "Key::Unbond({})", account_hash),
621            Key::ChainspecRegistry => write!(
622                f,
623                "Key::ChainspecRegistry({})",
624                base16::encode_lower(&PADDING_BYTES)
625            ),
626            Key::ChecksumRegistry => {
627                write!(
628                    f,
629                    "Key::ChecksumRegistry({})",
630                    base16::encode_lower(&PADDING_BYTES)
631                )
632            }
633        }
634    }
635}
636
637impl Debug for Key {
638    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
639        write!(f, "{}", self)
640    }
641}
642
643impl Tagged<KeyTag> for Key {
644    fn tag(&self) -> KeyTag {
645        match self {
646            Key::Account(_) => KeyTag::Account,
647            Key::Hash(_) => KeyTag::Hash,
648            Key::URef(_) => KeyTag::URef,
649            Key::Transfer(_) => KeyTag::Transfer,
650            Key::DeployInfo(_) => KeyTag::DeployInfo,
651            Key::EraInfo(_) => KeyTag::EraInfo,
652            Key::Balance(_) => KeyTag::Balance,
653            Key::Bid(_) => KeyTag::Bid,
654            Key::Withdraw(_) => KeyTag::Withdraw,
655            Key::Dictionary(_) => KeyTag::Dictionary,
656            Key::SystemContractRegistry => KeyTag::SystemContractRegistry,
657            Key::EraSummary => KeyTag::EraSummary,
658            Key::Unbond(_) => KeyTag::Unbond,
659            Key::ChainspecRegistry => KeyTag::ChainspecRegistry,
660            Key::ChecksumRegistry => KeyTag::ChecksumRegistry,
661        }
662    }
663}
664
665impl Tagged<u8> for Key {
666    fn tag(&self) -> u8 {
667        let key_tag: KeyTag = self.tag();
668        key_tag as u8
669    }
670}
671
672impl From<URef> for Key {
673    fn from(uref: URef) -> Key {
674        Key::URef(uref)
675    }
676}
677
678impl From<AccountHash> for Key {
679    fn from(account_hash: AccountHash) -> Key {
680        Key::Account(account_hash)
681    }
682}
683
684impl From<TransferAddr> for Key {
685    fn from(transfer_addr: TransferAddr) -> Key {
686        Key::Transfer(transfer_addr)
687    }
688}
689
690impl From<ContractHash> for Key {
691    fn from(contract_hash: ContractHash) -> Key {
692        Key::Hash(contract_hash.value())
693    }
694}
695
696impl From<ContractWasmHash> for Key {
697    fn from(wasm_hash: ContractWasmHash) -> Key {
698        Key::Hash(wasm_hash.value())
699    }
700}
701
702impl From<ContractPackageHash> for Key {
703    fn from(package_hash: ContractPackageHash) -> Key {
704        Key::Hash(package_hash.value())
705    }
706}
707
708impl ToBytes for Key {
709    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
710        let mut result = bytesrepr::unchecked_allocate_buffer(self);
711        self.write_bytes(&mut result)?;
712        Ok(result)
713    }
714
715    fn serialized_length(&self) -> usize {
716        match self {
717            Key::Account(account_hash) => {
718                KEY_ID_SERIALIZED_LENGTH + account_hash.serialized_length()
719            }
720            Key::Hash(_) => KEY_HASH_SERIALIZED_LENGTH,
721            Key::URef(_) => KEY_UREF_SERIALIZED_LENGTH,
722            Key::Transfer(_) => KEY_TRANSFER_SERIALIZED_LENGTH,
723            Key::DeployInfo(_) => KEY_DEPLOY_INFO_SERIALIZED_LENGTH,
724            Key::EraInfo(_) => KEY_ERA_INFO_SERIALIZED_LENGTH,
725            Key::Balance(_) => KEY_BALANCE_SERIALIZED_LENGTH,
726            Key::Bid(_) => KEY_BID_SERIALIZED_LENGTH,
727            Key::Withdraw(_) => KEY_WITHDRAW_SERIALIZED_LENGTH,
728            Key::Dictionary(_) => KEY_DICTIONARY_SERIALIZED_LENGTH,
729            Key::SystemContractRegistry => KEY_SYSTEM_CONTRACT_REGISTRY_SERIALIZED_LENGTH,
730            Key::EraSummary => KEY_ERA_SUMMARY_SERIALIZED_LENGTH,
731            Key::Unbond(_) => KEY_UNBOND_SERIALIZED_LENGTH,
732            Key::ChainspecRegistry => KEY_CHAINSPEC_REGISTRY_SERIALIZED_LENGTH,
733            Key::ChecksumRegistry => KEY_CHECKSUM_REGISTRY_SERIALIZED_LENGTH,
734        }
735    }
736
737    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
738        writer.push(self.tag());
739        match self {
740            Key::Account(account_hash) => account_hash.write_bytes(writer),
741            Key::Hash(hash) => hash.write_bytes(writer),
742            Key::URef(uref) => uref.write_bytes(writer),
743            Key::Transfer(addr) => addr.write_bytes(writer),
744            Key::DeployInfo(deploy_hash) => deploy_hash.write_bytes(writer),
745            Key::EraInfo(era_id) => era_id.write_bytes(writer),
746            Key::Balance(uref_addr) => uref_addr.write_bytes(writer),
747            Key::Bid(account_hash) => account_hash.write_bytes(writer),
748            Key::Withdraw(account_hash) => account_hash.write_bytes(writer),
749            Key::Dictionary(addr) => addr.write_bytes(writer),
750            Key::Unbond(account_hash) => account_hash.write_bytes(writer),
751            Key::SystemContractRegistry
752            | Key::EraSummary
753            | Key::ChainspecRegistry
754            | Key::ChecksumRegistry => PADDING_BYTES.write_bytes(writer),
755        }
756    }
757}
758
759impl FromBytes for Key {
760    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
761        let (tag, remainder) = u8::from_bytes(bytes)?;
762        match tag {
763            tag if tag == KeyTag::Account as u8 => {
764                let (account_hash, rem) = AccountHash::from_bytes(remainder)?;
765                Ok((Key::Account(account_hash), rem))
766            }
767            tag if tag == KeyTag::Hash as u8 => {
768                let (hash, rem) = HashAddr::from_bytes(remainder)?;
769                Ok((Key::Hash(hash), rem))
770            }
771            tag if tag == KeyTag::URef as u8 => {
772                let (uref, rem) = URef::from_bytes(remainder)?;
773                Ok((Key::URef(uref), rem))
774            }
775            tag if tag == KeyTag::Transfer as u8 => {
776                let (transfer_addr, rem) = TransferAddr::from_bytes(remainder)?;
777                Ok((Key::Transfer(transfer_addr), rem))
778            }
779            tag if tag == KeyTag::DeployInfo as u8 => {
780                let (deploy_hash, rem) = DeployHash::from_bytes(remainder)?;
781                Ok((Key::DeployInfo(deploy_hash), rem))
782            }
783            tag if tag == KeyTag::EraInfo as u8 => {
784                let (era_id, rem) = EraId::from_bytes(remainder)?;
785                Ok((Key::EraInfo(era_id), rem))
786            }
787            tag if tag == KeyTag::Balance as u8 => {
788                let (uref_addr, rem) = URefAddr::from_bytes(remainder)?;
789                Ok((Key::Balance(uref_addr), rem))
790            }
791            tag if tag == KeyTag::Bid as u8 => {
792                let (account_hash, rem) = AccountHash::from_bytes(remainder)?;
793                Ok((Key::Bid(account_hash), rem))
794            }
795            tag if tag == KeyTag::Withdraw as u8 => {
796                let (account_hash, rem) = AccountHash::from_bytes(remainder)?;
797                Ok((Key::Withdraw(account_hash), rem))
798            }
799            tag if tag == KeyTag::Dictionary as u8 => {
800                let (addr, rem) = DictionaryAddr::from_bytes(remainder)?;
801                Ok((Key::Dictionary(addr), rem))
802            }
803            tag if tag == KeyTag::SystemContractRegistry as u8 => {
804                let (_, rem) = <[u8; 32]>::from_bytes(remainder)?;
805                Ok((Key::SystemContractRegistry, rem))
806            }
807            tag if tag == KeyTag::EraSummary as u8 => {
808                let (_, rem) = <[u8; 32]>::from_bytes(remainder)?;
809                Ok((Key::EraSummary, rem))
810            }
811            tag if tag == KeyTag::Unbond as u8 => {
812                let (account_hash, rem) = AccountHash::from_bytes(remainder)?;
813                Ok((Key::Unbond(account_hash), rem))
814            }
815            tag if tag == KeyTag::ChainspecRegistry as u8 => {
816                let (_, rem) = <[u8; 32]>::from_bytes(remainder)?;
817                Ok((Key::ChainspecRegistry, rem))
818            }
819            tag if tag == KeyTag::ChecksumRegistry as u8 => {
820                let (_, rem) = <[u8; 32]>::from_bytes(remainder)?;
821                Ok((Key::ChecksumRegistry, rem))
822            }
823            _ => Err(Error::Formatting),
824        }
825    }
826}
827
828#[allow(dead_code)]
829fn please_add_to_distribution_impl(key: Key) {
830    // If you've been forced to come here, you likely need to add your variant to the
831    // `Distribution` impl for `Key`.
832    match key {
833        Key::Account(_) => unimplemented!(),
834        Key::Hash(_) => unimplemented!(),
835        Key::URef(_) => unimplemented!(),
836        Key::Transfer(_) => unimplemented!(),
837        Key::DeployInfo(_) => unimplemented!(),
838        Key::EraInfo(_) => unimplemented!(),
839        Key::Balance(_) => unimplemented!(),
840        Key::Bid(_) => unimplemented!(),
841        Key::Withdraw(_) => unimplemented!(),
842        Key::Dictionary(_) => unimplemented!(),
843        Key::SystemContractRegistry => unimplemented!(),
844        Key::EraSummary => unimplemented!(),
845        Key::Unbond(_) => unimplemented!(),
846        Key::ChainspecRegistry => unimplemented!(),
847        Key::ChecksumRegistry => unimplemented!(),
848    }
849}
850
851impl Distribution<Key> for Standard {
852    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Key {
853        match rng.gen_range(0..=14) {
854            0 => Key::Account(rng.gen()),
855            1 => Key::Hash(rng.gen()),
856            2 => Key::URef(rng.gen()),
857            3 => Key::Transfer(rng.gen()),
858            4 => Key::DeployInfo(rng.gen()),
859            5 => Key::EraInfo(rng.gen()),
860            6 => Key::Balance(rng.gen()),
861            7 => Key::Bid(rng.gen()),
862            8 => Key::Withdraw(rng.gen()),
863            9 => Key::Dictionary(rng.gen()),
864            10 => Key::SystemContractRegistry,
865            11 => Key::EraSummary,
866            12 => Key::Unbond(rng.gen()),
867            13 => Key::ChainspecRegistry,
868            14 => Key::ChecksumRegistry,
869            _ => unreachable!(),
870        }
871    }
872}
873
874mod serde_helpers {
875    use super::*;
876
877    #[derive(Serialize, Deserialize)]
878    pub(super) enum HumanReadable {
879        Account(String),
880        Hash(String),
881        URef(String),
882        Transfer(String),
883        DeployInfo(String),
884        EraInfo(String),
885        Balance(String),
886        Bid(String),
887        Withdraw(String),
888        Dictionary(String),
889        SystemContractRegistry(String),
890        EraSummary(String),
891        Unbond(String),
892        ChainspecRegistry(String),
893        ChecksumRegistry(String),
894    }
895
896    impl From<&Key> for HumanReadable {
897        fn from(key: &Key) -> Self {
898            let formatted_string = key.to_formatted_string();
899            match key {
900                Key::Account(_) => HumanReadable::Account(formatted_string),
901                Key::Hash(_) => HumanReadable::Hash(formatted_string),
902                Key::URef(_) => HumanReadable::URef(formatted_string),
903                Key::Transfer(_) => HumanReadable::Transfer(formatted_string),
904                Key::DeployInfo(_) => HumanReadable::DeployInfo(formatted_string),
905                Key::EraInfo(_) => HumanReadable::EraInfo(formatted_string),
906                Key::Balance(_) => HumanReadable::Balance(formatted_string),
907                Key::Bid(_) => HumanReadable::Bid(formatted_string),
908                Key::Withdraw(_) => HumanReadable::Withdraw(formatted_string),
909                Key::Dictionary(_) => HumanReadable::Dictionary(formatted_string),
910                Key::SystemContractRegistry => {
911                    HumanReadable::SystemContractRegistry(formatted_string)
912                }
913                Key::EraSummary => HumanReadable::EraSummary(formatted_string),
914                Key::Unbond(_) => HumanReadable::Unbond(formatted_string),
915                Key::ChainspecRegistry => HumanReadable::ChainspecRegistry(formatted_string),
916                Key::ChecksumRegistry => HumanReadable::ChecksumRegistry(formatted_string),
917            }
918        }
919    }
920
921    impl TryFrom<HumanReadable> for Key {
922        type Error = FromStrError;
923
924        fn try_from(helper: HumanReadable) -> Result<Self, Self::Error> {
925            match helper {
926                HumanReadable::Account(formatted_string)
927                | HumanReadable::Hash(formatted_string)
928                | HumanReadable::URef(formatted_string)
929                | HumanReadable::Transfer(formatted_string)
930                | HumanReadable::DeployInfo(formatted_string)
931                | HumanReadable::EraInfo(formatted_string)
932                | HumanReadable::Balance(formatted_string)
933                | HumanReadable::Bid(formatted_string)
934                | HumanReadable::Withdraw(formatted_string)
935                | HumanReadable::Dictionary(formatted_string)
936                | HumanReadable::SystemContractRegistry(formatted_string)
937                | HumanReadable::EraSummary(formatted_string)
938                | HumanReadable::Unbond(formatted_string)
939                | HumanReadable::ChainspecRegistry(formatted_string)
940                | HumanReadable::ChecksumRegistry(formatted_string) => {
941                    Key::from_formatted_str(&formatted_string)
942                }
943            }
944        }
945    }
946
947    #[derive(Serialize)]
948    pub(super) enum BinarySerHelper<'a> {
949        Account(&'a AccountHash),
950        Hash(&'a HashAddr),
951        URef(&'a URef),
952        Transfer(&'a TransferAddr),
953        DeployInfo(&'a DeployHash),
954        EraInfo(&'a EraId),
955        Balance(&'a URefAddr),
956        Bid(&'a AccountHash),
957        Withdraw(&'a AccountHash),
958        Dictionary(&'a HashAddr),
959        SystemContractRegistry,
960        EraSummary,
961        Unbond(&'a AccountHash),
962        ChainspecRegistry,
963        ChecksumRegistry,
964    }
965
966    impl<'a> From<&'a Key> for BinarySerHelper<'a> {
967        fn from(key: &'a Key) -> Self {
968            match key {
969                Key::Account(account_hash) => BinarySerHelper::Account(account_hash),
970                Key::Hash(hash_addr) => BinarySerHelper::Hash(hash_addr),
971                Key::URef(uref) => BinarySerHelper::URef(uref),
972                Key::Transfer(transfer_addr) => BinarySerHelper::Transfer(transfer_addr),
973                Key::DeployInfo(deploy_hash) => BinarySerHelper::DeployInfo(deploy_hash),
974                Key::EraInfo(era_id) => BinarySerHelper::EraInfo(era_id),
975                Key::Balance(uref_addr) => BinarySerHelper::Balance(uref_addr),
976                Key::Bid(account_hash) => BinarySerHelper::Bid(account_hash),
977                Key::Withdraw(account_hash) => BinarySerHelper::Withdraw(account_hash),
978                Key::Dictionary(addr) => BinarySerHelper::Dictionary(addr),
979                Key::SystemContractRegistry => BinarySerHelper::SystemContractRegistry,
980                Key::EraSummary => BinarySerHelper::EraSummary,
981                Key::Unbond(account_hash) => BinarySerHelper::Unbond(account_hash),
982                Key::ChainspecRegistry => BinarySerHelper::ChainspecRegistry,
983                Key::ChecksumRegistry => BinarySerHelper::ChecksumRegistry,
984            }
985        }
986    }
987
988    #[derive(Deserialize)]
989    pub(super) enum BinaryDeserHelper {
990        Account(AccountHash),
991        Hash(HashAddr),
992        URef(URef),
993        Transfer(TransferAddr),
994        DeployInfo(DeployHash),
995        EraInfo(EraId),
996        Balance(URefAddr),
997        Bid(AccountHash),
998        Withdraw(AccountHash),
999        Dictionary(DictionaryAddr),
1000        SystemContractRegistry,
1001        EraSummary,
1002        Unbond(AccountHash),
1003        ChainspecRegistry,
1004        ChecksumRegistry,
1005    }
1006
1007    impl From<BinaryDeserHelper> for Key {
1008        fn from(helper: BinaryDeserHelper) -> Self {
1009            match helper {
1010                BinaryDeserHelper::Account(account_hash) => Key::Account(account_hash),
1011                BinaryDeserHelper::Hash(hash_addr) => Key::Hash(hash_addr),
1012                BinaryDeserHelper::URef(uref) => Key::URef(uref),
1013                BinaryDeserHelper::Transfer(transfer_addr) => Key::Transfer(transfer_addr),
1014                BinaryDeserHelper::DeployInfo(deploy_hash) => Key::DeployInfo(deploy_hash),
1015                BinaryDeserHelper::EraInfo(era_id) => Key::EraInfo(era_id),
1016                BinaryDeserHelper::Balance(uref_addr) => Key::Balance(uref_addr),
1017                BinaryDeserHelper::Bid(account_hash) => Key::Bid(account_hash),
1018                BinaryDeserHelper::Withdraw(account_hash) => Key::Withdraw(account_hash),
1019                BinaryDeserHelper::Dictionary(addr) => Key::Dictionary(addr),
1020                BinaryDeserHelper::SystemContractRegistry => Key::SystemContractRegistry,
1021                BinaryDeserHelper::EraSummary => Key::EraSummary,
1022                BinaryDeserHelper::Unbond(account_hash) => Key::Unbond(account_hash),
1023                BinaryDeserHelper::ChainspecRegistry => Key::ChainspecRegistry,
1024                BinaryDeserHelper::ChecksumRegistry => Key::ChecksumRegistry,
1025            }
1026        }
1027    }
1028}
1029
1030impl Serialize for Key {
1031    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1032        if serializer.is_human_readable() {
1033            serde_helpers::HumanReadable::from(self).serialize(serializer)
1034        } else {
1035            serde_helpers::BinarySerHelper::from(self).serialize(serializer)
1036        }
1037    }
1038}
1039
1040impl<'de> Deserialize<'de> for Key {
1041    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
1042        if deserializer.is_human_readable() {
1043            let human_readable = serde_helpers::HumanReadable::deserialize(deserializer)?;
1044            Key::try_from(human_readable).map_err(SerdeError::custom)
1045        } else {
1046            let binary_helper = serde_helpers::BinaryDeserHelper::deserialize(deserializer)?;
1047            Ok(Key::from(binary_helper))
1048        }
1049    }
1050}
1051
1052#[cfg(test)]
1053mod tests {
1054    use std::string::ToString;
1055
1056    use serde_json::json;
1057
1058    use super::*;
1059    use crate::{
1060        account::ACCOUNT_HASH_FORMATTED_STRING_PREFIX,
1061        bytesrepr::{Error, FromBytes},
1062        transfer::TRANSFER_ADDR_FORMATTED_STRING_PREFIX,
1063        uref::UREF_FORMATTED_STRING_PREFIX,
1064        AccessRights, URef,
1065    };
1066
1067    const ACCOUNT_KEY: Key = Key::Account(AccountHash::new([42; 32]));
1068    const HASH_KEY: Key = Key::Hash([42; 32]);
1069    const UREF_KEY: Key = Key::URef(URef::new([42; 32], AccessRights::READ));
1070    const TRANSFER_KEY: Key = Key::Transfer(TransferAddr::new([42; 32]));
1071    const DEPLOY_INFO_KEY: Key = Key::DeployInfo(DeployHash::new([42; 32]));
1072    const ERA_INFO_KEY: Key = Key::EraInfo(EraId::new(42));
1073    const BALANCE_KEY: Key = Key::Balance([42; 32]);
1074    const BID_KEY: Key = Key::Bid(AccountHash::new([42; 32]));
1075    const WITHDRAW_KEY: Key = Key::Withdraw(AccountHash::new([42; 32]));
1076    const DICTIONARY_KEY: Key = Key::Dictionary([42; 32]);
1077    const SYSTEM_CONTRACT_REGISTRY_KEY: Key = Key::SystemContractRegistry;
1078    const ERA_SUMMARY_KEY: Key = Key::EraSummary;
1079    const UNBOND_KEY: Key = Key::Unbond(AccountHash::new([42; 32]));
1080    const CHAINSPEC_REGISTRY_KEY: Key = Key::ChainspecRegistry;
1081    const CHECKSUM_REGISTRY_KEY: Key = Key::ChecksumRegistry;
1082    const KEYS: &[Key] = &[
1083        ACCOUNT_KEY,
1084        HASH_KEY,
1085        UREF_KEY,
1086        TRANSFER_KEY,
1087        DEPLOY_INFO_KEY,
1088        ERA_INFO_KEY,
1089        BALANCE_KEY,
1090        BID_KEY,
1091        WITHDRAW_KEY,
1092        DICTIONARY_KEY,
1093        SYSTEM_CONTRACT_REGISTRY_KEY,
1094        ERA_SUMMARY_KEY,
1095        UNBOND_KEY,
1096        CHAINSPEC_REGISTRY_KEY,
1097        CHECKSUM_REGISTRY_KEY,
1098    ];
1099    const HEX_STRING: &str = "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a";
1100
1101    fn test_readable(right: AccessRights, is_true: bool) {
1102        assert_eq!(right.is_readable(), is_true)
1103    }
1104
1105    #[test]
1106    fn test_is_readable() {
1107        test_readable(AccessRights::READ, true);
1108        test_readable(AccessRights::READ_ADD, true);
1109        test_readable(AccessRights::READ_WRITE, true);
1110        test_readable(AccessRights::READ_ADD_WRITE, true);
1111        test_readable(AccessRights::ADD, false);
1112        test_readable(AccessRights::ADD_WRITE, false);
1113        test_readable(AccessRights::WRITE, false);
1114    }
1115
1116    fn test_writable(right: AccessRights, is_true: bool) {
1117        assert_eq!(right.is_writeable(), is_true)
1118    }
1119
1120    #[test]
1121    fn test_is_writable() {
1122        test_writable(AccessRights::WRITE, true);
1123        test_writable(AccessRights::READ_WRITE, true);
1124        test_writable(AccessRights::ADD_WRITE, true);
1125        test_writable(AccessRights::READ, false);
1126        test_writable(AccessRights::ADD, false);
1127        test_writable(AccessRights::READ_ADD, false);
1128        test_writable(AccessRights::READ_ADD_WRITE, true);
1129    }
1130
1131    fn test_addable(right: AccessRights, is_true: bool) {
1132        assert_eq!(right.is_addable(), is_true)
1133    }
1134
1135    #[test]
1136    fn test_is_addable() {
1137        test_addable(AccessRights::ADD, true);
1138        test_addable(AccessRights::READ_ADD, true);
1139        test_addable(AccessRights::READ_WRITE, false);
1140        test_addable(AccessRights::ADD_WRITE, true);
1141        test_addable(AccessRights::READ, false);
1142        test_addable(AccessRights::WRITE, false);
1143        test_addable(AccessRights::READ_ADD_WRITE, true);
1144    }
1145
1146    #[test]
1147    fn should_display_key() {
1148        assert_eq!(
1149            format!("{}", ACCOUNT_KEY),
1150            format!("Key::Account({})", HEX_STRING)
1151        );
1152        assert_eq!(
1153            format!("{}", HASH_KEY),
1154            format!("Key::Hash({})", HEX_STRING)
1155        );
1156        assert_eq!(
1157            format!("{}", UREF_KEY),
1158            format!("Key::URef({}, READ)", HEX_STRING)
1159        );
1160        assert_eq!(
1161            format!("{}", TRANSFER_KEY),
1162            format!("Key::Transfer({})", HEX_STRING)
1163        );
1164        assert_eq!(
1165            format!("{}", DEPLOY_INFO_KEY),
1166            format!("Key::DeployInfo({})", HEX_STRING)
1167        );
1168        assert_eq!(
1169            format!("{}", ERA_INFO_KEY),
1170            "Key::EraInfo(era 42)".to_string()
1171        );
1172        assert_eq!(
1173            format!("{}", BALANCE_KEY),
1174            format!("Key::Balance({})", HEX_STRING)
1175        );
1176        assert_eq!(format!("{}", BID_KEY), format!("Key::Bid({})", HEX_STRING));
1177        assert_eq!(
1178            format!("{}", WITHDRAW_KEY),
1179            format!("Key::Withdraw({})", HEX_STRING)
1180        );
1181        assert_eq!(
1182            format!("{}", DICTIONARY_KEY),
1183            format!("Key::Dictionary({})", HEX_STRING)
1184        );
1185        assert_eq!(
1186            format!("{}", SYSTEM_CONTRACT_REGISTRY_KEY),
1187            format!(
1188                "Key::SystemContractRegistry({})",
1189                base16::encode_lower(&PADDING_BYTES)
1190            )
1191        );
1192        assert_eq!(
1193            format!("{}", ERA_SUMMARY_KEY),
1194            format!("Key::EraSummary({})", base16::encode_lower(&PADDING_BYTES))
1195        );
1196        assert_eq!(
1197            format!("{}", UNBOND_KEY),
1198            format!("Key::Unbond({})", HEX_STRING)
1199        );
1200        assert_eq!(
1201            format!("{}", CHAINSPEC_REGISTRY_KEY),
1202            format!(
1203                "Key::ChainspecRegistry({})",
1204                base16::encode_lower(&PADDING_BYTES)
1205            )
1206        );
1207        assert_eq!(
1208            format!("{}", CHECKSUM_REGISTRY_KEY),
1209            format!(
1210                "Key::ChecksumRegistry({})",
1211                base16::encode_lower(&PADDING_BYTES),
1212            )
1213        );
1214    }
1215
1216    #[test]
1217    fn abuse_vec_key() {
1218        // Prefix is 2^32-1 = shouldn't allocate that much
1219        let bytes: Vec<u8> = vec![255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
1220        let res: Result<(Vec<Key>, &[u8]), _> = FromBytes::from_bytes(&bytes);
1221        assert_eq!(
1222            res.expect_err("should fail"),
1223            Error::EarlyEndOfStream,
1224            "length prefix says 2^32-1, but there's not enough data in the stream"
1225        );
1226
1227        // Prefix is 2^32-2 = shouldn't allocate that much
1228        let bytes: Vec<u8> = vec![255, 255, 255, 254, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
1229        let res: Result<(Vec<Key>, &[u8]), _> = FromBytes::from_bytes(&bytes);
1230        assert_eq!(
1231            res.expect_err("should fail"),
1232            Error::EarlyEndOfStream,
1233            "length prefix says 2^32-2, but there's not enough data in the stream"
1234        );
1235
1236        // Valid prefix but not enough data in the stream
1237        let bytes: Vec<u8> = vec![0, 0, 0, 254, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
1238        let res: Result<(Vec<Key>, &[u8]), _> = FromBytes::from_bytes(&bytes);
1239        assert_eq!(
1240            res.expect_err("should fail"),
1241            Error::EarlyEndOfStream,
1242            "length prefix says 254, but there's not enough data in the stream"
1243        );
1244    }
1245
1246    #[test]
1247    fn check_key_account_getters() {
1248        let account = [42; 32];
1249        let account_hash = AccountHash::new(account);
1250        let key1 = Key::Account(account_hash);
1251        assert_eq!(key1.into_account(), Some(account_hash));
1252        assert!(key1.into_hash().is_none());
1253        assert!(key1.as_uref().is_none());
1254    }
1255
1256    #[test]
1257    fn check_key_hash_getters() {
1258        let hash = [42; KEY_HASH_LENGTH];
1259        let key1 = Key::Hash(hash);
1260        assert!(key1.into_account().is_none());
1261        assert_eq!(key1.into_hash(), Some(hash));
1262        assert!(key1.as_uref().is_none());
1263    }
1264
1265    #[test]
1266    fn check_key_uref_getters() {
1267        let uref = URef::new([42; 32], AccessRights::READ_ADD_WRITE);
1268        let key1 = Key::URef(uref);
1269        assert!(key1.into_account().is_none());
1270        assert!(key1.into_hash().is_none());
1271        assert_eq!(key1.as_uref(), Some(&uref));
1272    }
1273
1274    #[test]
1275    fn key_max_serialized_length() {
1276        let mut got_max = false;
1277        for key in KEYS {
1278            assert!(key.serialized_length() <= Key::max_serialized_length());
1279            if key.serialized_length() == Key::max_serialized_length() {
1280                got_max = true;
1281            }
1282        }
1283        assert!(
1284            got_max,
1285            "None of the Key variants has a serialized_length equal to \
1286            Key::max_serialized_length(), so Key::max_serialized_length() should be reduced"
1287        );
1288    }
1289
1290    #[test]
1291    fn should_parse_key_from_str() {
1292        for key in KEYS {
1293            let string = key.to_formatted_string();
1294            let parsed_key = Key::from_formatted_str(&string).unwrap();
1295            assert_eq!(parsed_key, *key, "{string} (key = {key:?})");
1296        }
1297    }
1298
1299    #[test]
1300    fn should_fail_to_parse_key_from_str() {
1301        assert!(
1302            Key::from_formatted_str(ACCOUNT_HASH_FORMATTED_STRING_PREFIX)
1303                .unwrap_err()
1304                .to_string()
1305                .starts_with("account-key from string error: ")
1306        );
1307        assert!(Key::from_formatted_str(HASH_PREFIX)
1308            .unwrap_err()
1309            .to_string()
1310            .starts_with("hash-key from string error: "));
1311        assert!(Key::from_formatted_str(UREF_FORMATTED_STRING_PREFIX)
1312            .unwrap_err()
1313            .to_string()
1314            .starts_with("uref-key from string error: "));
1315        assert!(
1316            Key::from_formatted_str(TRANSFER_ADDR_FORMATTED_STRING_PREFIX)
1317                .unwrap_err()
1318                .to_string()
1319                .starts_with("transfer-key from string error: ")
1320        );
1321        assert!(Key::from_formatted_str(DEPLOY_INFO_PREFIX)
1322            .unwrap_err()
1323            .to_string()
1324            .starts_with("deploy-info-key from string error: "));
1325        assert!(Key::from_formatted_str(ERA_INFO_PREFIX)
1326            .unwrap_err()
1327            .to_string()
1328            .starts_with("era-info-key from string error: "));
1329        assert!(Key::from_formatted_str(BALANCE_PREFIX)
1330            .unwrap_err()
1331            .to_string()
1332            .starts_with("balance-key from string error: "));
1333        assert!(Key::from_formatted_str(BID_PREFIX)
1334            .unwrap_err()
1335            .to_string()
1336            .starts_with("bid-key from string error: "));
1337        assert!(Key::from_formatted_str(WITHDRAW_PREFIX)
1338            .unwrap_err()
1339            .to_string()
1340            .starts_with("withdraw-key from string error: "));
1341        assert!(Key::from_formatted_str(DICTIONARY_PREFIX)
1342            .unwrap_err()
1343            .to_string()
1344            .starts_with("dictionary-key from string error: "));
1345        assert!(Key::from_formatted_str(SYSTEM_CONTRACT_REGISTRY_PREFIX)
1346            .unwrap_err()
1347            .to_string()
1348            .starts_with("system-contract-registry-key from string error: "));
1349        assert!(Key::from_formatted_str(ERA_SUMMARY_PREFIX)
1350            .unwrap_err()
1351            .to_string()
1352            .starts_with("era-summary-key from string error"));
1353        assert!(Key::from_formatted_str(UNBOND_PREFIX)
1354            .unwrap_err()
1355            .to_string()
1356            .starts_with("unbond-key from string error: "));
1357        assert!(Key::from_formatted_str(CHAINSPEC_REGISTRY_PREFIX)
1358            .unwrap_err()
1359            .to_string()
1360            .starts_with("chainspec-registry-key from string error: "));
1361        assert!(Key::from_formatted_str(CHECKSUM_REGISTRY_PREFIX)
1362            .unwrap_err()
1363            .to_string()
1364            .starts_with("checksum-registry-key from string error: "));
1365        let invalid_prefix = "a-0000000000000000000000000000000000000000000000000000000000000000";
1366        assert_eq!(
1367            Key::from_formatted_str(invalid_prefix)
1368                .unwrap_err()
1369                .to_string(),
1370            "unknown prefix for key"
1371        );
1372
1373        let missing_hyphen_prefix =
1374            "hash0000000000000000000000000000000000000000000000000000000000000000";
1375        assert_eq!(
1376            Key::from_formatted_str(missing_hyphen_prefix)
1377                .unwrap_err()
1378                .to_string(),
1379            "unknown prefix for key"
1380        );
1381
1382        let no_prefix = "0000000000000000000000000000000000000000000000000000000000000000";
1383        assert_eq!(
1384            Key::from_formatted_str(no_prefix).unwrap_err().to_string(),
1385            "unknown prefix for key"
1386        );
1387    }
1388
1389    #[test]
1390    fn key_to_json() {
1391        let expected_json = &[
1392            json!({ "Account": format!("account-hash-{}", HEX_STRING) }),
1393            json!({ "Hash": format!("hash-{}", HEX_STRING) }),
1394            json!({ "URef": format!("uref-{}-001", HEX_STRING) }),
1395            json!({ "Transfer": format!("transfer-{}", HEX_STRING) }),
1396            json!({ "DeployInfo": format!("deploy-{}", HEX_STRING) }),
1397            json!({ "EraInfo": "era-42" }),
1398            json!({ "Balance": format!("balance-{}", HEX_STRING) }),
1399            json!({ "Bid": format!("bid-{}", HEX_STRING) }),
1400            json!({ "Withdraw": format!("withdraw-{}", HEX_STRING) }),
1401            json!({ "Dictionary": format!("dictionary-{}", HEX_STRING) }),
1402            json!({
1403                "SystemContractRegistry":
1404                    format!(
1405                        "system-contract-registry-{}",
1406                        base16::encode_lower(&PADDING_BYTES)
1407                    )
1408            }),
1409            json!({
1410                "EraSummary": format!("era-summary-{}", base16::encode_lower(&PADDING_BYTES))
1411            }),
1412            json!({ "Unbond": format!("unbond-{}", HEX_STRING) }),
1413            json!({
1414                "ChainspecRegistry":
1415                    format!(
1416                        "chainspec-registry-{}",
1417                        base16::encode_lower(&PADDING_BYTES)
1418                    )
1419            }),
1420            json!({
1421                "ChecksumRegistry":
1422                    format!("checksum-registry-{}", base16::encode_lower(&PADDING_BYTES))
1423            }),
1424        ];
1425
1426        assert_eq!(
1427            KEYS.len(),
1428            expected_json.len(),
1429            "There should be exactly one expected JSON string per test key"
1430        );
1431
1432        for (key, expected_json_key) in KEYS.iter().zip(expected_json.iter()) {
1433            assert_eq!(serde_json::to_value(key).unwrap(), *expected_json_key);
1434        }
1435    }
1436
1437    #[test]
1438    fn serialization_roundtrip_bincode() {
1439        for key in KEYS {
1440            let encoded = bincode::serialize(key).unwrap();
1441            let decoded = bincode::deserialize(&encoded).unwrap();
1442            assert_eq!(key, &decoded);
1443        }
1444    }
1445
1446    #[test]
1447    fn serialization_roundtrip_json() {
1448        let round_trip = |key: &Key| {
1449            let encoded = serde_json::to_value(key).unwrap();
1450            let decoded = serde_json::from_value(encoded).unwrap();
1451            assert_eq!(key, &decoded);
1452        };
1453
1454        for key in KEYS {
1455            round_trip(key);
1456        }
1457
1458        let zeros = [0; BLAKE2B_DIGEST_LENGTH];
1459
1460        round_trip(&Key::Account(AccountHash::new(zeros)));
1461        round_trip(&Key::Hash(zeros));
1462        round_trip(&Key::URef(URef::new(zeros, AccessRights::READ)));
1463        round_trip(&Key::Transfer(TransferAddr::new(zeros)));
1464        round_trip(&Key::DeployInfo(DeployHash::new(zeros)));
1465        round_trip(&Key::EraInfo(EraId::from(0)));
1466        round_trip(&Key::Balance(URef::new(zeros, AccessRights::READ).addr()));
1467        round_trip(&Key::Bid(AccountHash::new(zeros)));
1468        round_trip(&Key::Withdraw(AccountHash::new(zeros)));
1469        round_trip(&Key::Dictionary(zeros));
1470        round_trip(&Key::SystemContractRegistry);
1471        round_trip(&Key::EraSummary);
1472        round_trip(&Key::Unbond(AccountHash::new(zeros)));
1473        round_trip(&Key::ChainspecRegistry);
1474        round_trip(&Key::ChecksumRegistry);
1475    }
1476}