casper_types/
stored_value.rs

1mod global_state_identifier;
2mod type_mismatch;
3
4use alloc::{
5    boxed::Box,
6    string::{String, ToString},
7    vec::Vec,
8};
9use core::{convert::TryFrom, fmt::Debug};
10
11#[cfg(feature = "datasize")]
12use datasize::DataSize;
13#[cfg(feature = "json-schema")]
14use schemars::JsonSchema;
15use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
16use serde_bytes::ByteBuf;
17
18use crate::{
19    account::Account,
20    addressable_entity::NamedKeyValue,
21    bytesrepr::{self, Bytes, Error, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
22    contract_messages::{MessageChecksum, MessageTopicSummary},
23    contract_wasm::ContractWasm,
24    contracts::{Contract, ContractPackage},
25    package::Package,
26    system::{
27        auction::{Bid, BidKind, EraInfo, Unbond, UnbondingPurse, WithdrawPurse},
28        prepayment::PrepaymentKind,
29    },
30    AddressableEntity, ByteCode, CLValue, DeployInfo, EntryPointValue, TransferV1,
31};
32pub use global_state_identifier::GlobalStateIdentifier;
33pub use type_mismatch::TypeMismatch;
34
35/// Tag used to discriminate between different variants of `StoredValue`.
36#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
37#[repr(u8)]
38pub enum StoredValueTag {
39    /// A CLValue.
40    CLValue = 0,
41    /// An account.
42    Account = 1,
43    /// Contract wasm.
44    ContractWasm = 2,
45    /// A contract.
46    Contract = 3,
47    /// A contract package.
48    ContractPackage = 4,
49    /// A version 1 transfer.
50    Transfer = 5,
51    /// Info about a deploy.
52    DeployInfo = 6,
53    /// Info about an era.
54    EraInfo = 7,
55    /// A bid.
56    Bid = 8,
57    /// Withdraw information.
58    Withdraw = 9,
59    /// Unbonding information.
60    Unbonding = 10,
61    /// An `AddressableEntity`.
62    BidKind = 11,
63    /// A `Package`.
64    Package = 12,
65    /// A record of byte code.
66    AddressableEntity = 13,
67    /// A record of byte code.
68    ByteCode = 14,
69    /// A message topic.
70    MessageTopic = 15,
71    /// A message digest.
72    Message = 16,
73    /// A NamedKey record.
74    NamedKey = 17,
75    /// A prepayment record.
76    Prepayment = 18,
77    /// An entrypoint record.
78    EntryPoint = 19,
79    /// Raw bytes.
80    RawBytes = 20,
81}
82
83/// A value stored in Global State.
84#[allow(clippy::large_enum_variant)]
85#[derive(Eq, PartialEq, Clone, Debug)]
86#[cfg_attr(feature = "datasize", derive(DataSize))]
87#[cfg_attr(
88    feature = "json-schema",
89    derive(JsonSchema),
90    schemars(with = "serde_helpers::HumanReadableDeserHelper")
91)]
92pub enum StoredValue {
93    /// A CLValue.
94    CLValue(CLValue),
95    /// An account.
96    Account(Account),
97    /// Contract wasm.
98    ContractWasm(ContractWasm),
99    /// A contract.
100    Contract(Contract),
101    /// A contract package.
102    ContractPackage(ContractPackage),
103    /// A version 1 transfer.
104    Transfer(TransferV1),
105    /// Info about a deploy.
106    DeployInfo(DeployInfo),
107    /// Info about an era.
108    EraInfo(EraInfo),
109    /// Variant that stores [`Bid`].
110    Bid(Box<Bid>),
111    /// Variant that stores withdraw information.
112    Withdraw(Vec<WithdrawPurse>),
113    /// Unbonding information.
114    Unbonding(Vec<UnbondingPurse>),
115    /// An `AddressableEntity`.
116    AddressableEntity(AddressableEntity),
117    /// Variant that stores [`BidKind`].
118    BidKind(BidKind),
119    /// A smart contract `Package`.
120    SmartContract(Package),
121    /// A record of byte code.
122    ByteCode(ByteCode),
123    /// Variant that stores a message topic.
124    MessageTopic(MessageTopicSummary),
125    /// Variant that stores a message digest.
126    Message(MessageChecksum),
127    /// A NamedKey record.
128    NamedKey(NamedKeyValue),
129    /// A prepayment record.
130    Prepayment(PrepaymentKind),
131    /// An entrypoint record.
132    EntryPoint(EntryPointValue),
133    /// Raw bytes. Similar to a [`crate::StoredValue::CLValue`] but does not incur overhead of a
134    /// [`crate::CLValue`] and [`crate::CLType`].
135    RawBytes(#[cfg_attr(feature = "json-schema", schemars(with = "String"))] Vec<u8>),
136}
137
138impl StoredValue {
139    /// Returns a reference to the wrapped `CLValue` if this is a `CLValue` variant.
140    pub fn as_cl_value(&self) -> Option<&CLValue> {
141        match self {
142            StoredValue::CLValue(cl_value) => Some(cl_value),
143            _ => None,
144        }
145    }
146
147    /// Returns a reference to the wrapped `Account` if this is an `Account` variant.
148    pub fn as_account(&self) -> Option<&Account> {
149        match self {
150            StoredValue::Account(account) => Some(account),
151            _ => None,
152        }
153    }
154
155    /// Returns a reference to the wrapped `ByteCode` if this is a `ByteCode` variant.
156    pub fn as_byte_code(&self) -> Option<&ByteCode> {
157        match self {
158            StoredValue::ByteCode(byte_code) => Some(byte_code),
159            _ => None,
160        }
161    }
162
163    pub fn as_contract_wasm(&self) -> Option<&ContractWasm> {
164        match self {
165            StoredValue::ContractWasm(contract_wasm) => Some(contract_wasm),
166            _ => None,
167        }
168    }
169
170    /// Returns a reference to the wrapped `Contract` if this is a `Contract` variant.
171    pub fn as_contract(&self) -> Option<&Contract> {
172        match self {
173            StoredValue::Contract(contract) => Some(contract),
174            _ => None,
175        }
176    }
177
178    /// Returns a reference to the wrapped `Package` if this is a `Package` variant.
179    pub fn as_package(&self) -> Option<&Package> {
180        match self {
181            StoredValue::SmartContract(package) => Some(package),
182            _ => None,
183        }
184    }
185
186    /// Returns a reference to the wrapped `ContractPackage` if this is a `ContractPackage` variant.
187    pub fn as_contract_package(&self) -> Option<&ContractPackage> {
188        match self {
189            StoredValue::ContractPackage(package) => Some(package),
190            _ => None,
191        }
192    }
193
194    /// Returns a reference to the wrapped `TransferV1` if this is a `Transfer` variant.
195    pub fn as_transfer(&self) -> Option<&TransferV1> {
196        match self {
197            StoredValue::Transfer(transfer_v1) => Some(transfer_v1),
198            _ => None,
199        }
200    }
201
202    /// Returns a reference to the wrapped `DeployInfo` if this is a `DeployInfo` variant.
203    pub fn as_deploy_info(&self) -> Option<&DeployInfo> {
204        match self {
205            StoredValue::DeployInfo(deploy_info) => Some(deploy_info),
206            _ => None,
207        }
208    }
209
210    /// Returns a reference to the wrapped `EraInfo` if this is an `EraInfo` variant.
211    pub fn as_era_info(&self) -> Option<&EraInfo> {
212        match self {
213            StoredValue::EraInfo(era_info) => Some(era_info),
214            _ => None,
215        }
216    }
217
218    /// Returns a reference to the wrapped `Bid` if this is a `Bid` variant.
219    pub fn as_bid(&self) -> Option<&Bid> {
220        match self {
221            StoredValue::Bid(bid) => Some(bid),
222            _ => None,
223        }
224    }
225
226    /// Returns a reference to the wrapped list of `WithdrawPurse`s if this is a `Withdraw` variant.
227    pub fn as_withdraw(&self) -> Option<&Vec<WithdrawPurse>> {
228        match self {
229            StoredValue::Withdraw(withdraw_purses) => Some(withdraw_purses),
230            _ => None,
231        }
232    }
233
234    /// Returns a reference to the wrapped list of `UnbondingPurse`s if this is an `Unbonding`
235    /// variant.
236    pub fn as_unbonding(&self) -> Option<&Vec<UnbondingPurse>> {
237        match self {
238            StoredValue::Unbonding(unbonding_purses) => Some(unbonding_purses),
239            _ => None,
240        }
241    }
242
243    /// Returns a reference to the wrapped list of `UnbondingPurse`s if this is an `Unbonding`
244    /// variant.
245    pub fn as_unbond(&self) -> Option<&Unbond> {
246        match self {
247            StoredValue::BidKind(BidKind::Unbond(unbond)) => Some(unbond),
248            _ => None,
249        }
250    }
251
252    /// Returns a reference to the wrapped `AddressableEntity` if this is an `AddressableEntity`
253    /// variant.
254    pub fn as_addressable_entity(&self) -> Option<&AddressableEntity> {
255        match self {
256            StoredValue::AddressableEntity(entity) => Some(entity),
257            _ => None,
258        }
259    }
260
261    /// Returns a reference to the wrapped `MessageTopicSummary` if this is a `MessageTopic`
262    /// variant.
263    pub fn as_message_topic_summary(&self) -> Option<&MessageTopicSummary> {
264        match self {
265            StoredValue::MessageTopic(summary) => Some(summary),
266            _ => None,
267        }
268    }
269
270    /// Returns a reference to the wrapped `MessageChecksum` if this is a `Message`
271    /// variant.
272    pub fn as_message_checksum(&self) -> Option<&MessageChecksum> {
273        match self {
274            StoredValue::Message(checksum) => Some(checksum),
275            _ => None,
276        }
277    }
278
279    /// Returns a reference to the wrapped `BidKind` if this is a `BidKind` variant.
280    pub fn as_bid_kind(&self) -> Option<&BidKind> {
281        match self {
282            StoredValue::BidKind(bid_kind) => Some(bid_kind),
283            _ => None,
284        }
285    }
286
287    /// Returns raw bytes if this is a `RawBytes` variant.
288    pub fn as_raw_bytes(&self) -> Option<&[u8]> {
289        match self {
290            StoredValue::RawBytes(bytes) => Some(bytes),
291            _ => None,
292        }
293    }
294
295    /// Returns a reference to the wrapped `EntryPointValue` if this is a `EntryPointValue` variant.
296    pub fn as_entry_point_value(&self) -> Option<&EntryPointValue> {
297        match self {
298            StoredValue::EntryPoint(entry_point) => Some(entry_point),
299            _ => None,
300        }
301    }
302
303    /// Returns the `CLValue` if this is a `CLValue` variant.
304    pub fn into_cl_value(self) -> Option<CLValue> {
305        match self {
306            StoredValue::CLValue(cl_value) => Some(cl_value),
307            _ => None,
308        }
309    }
310
311    /// Returns the `Account` if this is an `Account` variant.
312    pub fn into_account(self) -> Option<Account> {
313        match self {
314            StoredValue::Account(account) => Some(account),
315            _ => None,
316        }
317    }
318
319    /// Returns the `ContractWasm` if this is a `ContractWasm` variant.
320    pub fn into_contract_wasm(self) -> Option<ContractWasm> {
321        match self {
322            StoredValue::ContractWasm(contract_wasm) => Some(contract_wasm),
323            _ => None,
324        }
325    }
326
327    /// Returns the `Contract` if this is a `Contract` variant.
328    pub fn into_contract(self) -> Option<Contract> {
329        match self {
330            StoredValue::Contract(contract) => Some(contract),
331            _ => None,
332        }
333    }
334
335    /// Returns the `ContractPackage` if this is a `ContractPackage` variant.
336    pub fn into_contract_package(self) -> Option<ContractPackage> {
337        match self {
338            StoredValue::ContractPackage(contract_package) => Some(contract_package),
339            _ => None,
340        }
341    }
342
343    /// Returns the `Package` if this is a `Package` variant.
344    pub fn into_package(self) -> Option<Package> {
345        match self {
346            StoredValue::SmartContract(package) => Some(package),
347            _ => None,
348        }
349    }
350
351    /// Returns the `TransferV1` if this is a `Transfer` variant.
352    pub fn into_legacy_transfer(self) -> Option<TransferV1> {
353        match self {
354            StoredValue::Transfer(transfer_v1) => Some(transfer_v1),
355            _ => None,
356        }
357    }
358
359    /// Returns the `DeployInfo` if this is a `DeployInfo` variant.
360    pub fn into_deploy_info(self) -> Option<DeployInfo> {
361        match self {
362            StoredValue::DeployInfo(deploy_info) => Some(deploy_info),
363            _ => None,
364        }
365    }
366
367    /// Returns the `EraInfo` if this is an `EraInfo` variant.
368    pub fn into_era_info(self) -> Option<EraInfo> {
369        match self {
370            StoredValue::EraInfo(era_info) => Some(era_info),
371            _ => None,
372        }
373    }
374
375    /// Returns the `Bid` if this is a `Bid` variant.
376    pub fn into_bid(self) -> Option<Bid> {
377        match self {
378            StoredValue::Bid(bid) => Some(*bid),
379            _ => None,
380        }
381    }
382
383    /// Returns the list of `WithdrawPurse`s if this is a `Withdraw` variant.
384    pub fn into_withdraw(self) -> Option<Vec<WithdrawPurse>> {
385        match self {
386            StoredValue::Withdraw(withdraw_purses) => Some(withdraw_purses),
387            _ => None,
388        }
389    }
390
391    /// Returns the list of `UnbondingPurse`s if this is an `Unbonding` variant.
392    pub fn into_unbonding(self) -> Option<Vec<UnbondingPurse>> {
393        match self {
394            StoredValue::Unbonding(unbonding_purses) => Some(unbonding_purses),
395            _ => None,
396        }
397    }
398
399    /// Returns the `AddressableEntity` if this is an `AddressableEntity` variant.
400    pub fn into_addressable_entity(self) -> Option<AddressableEntity> {
401        match self {
402            StoredValue::AddressableEntity(entity) => Some(entity),
403            _ => None,
404        }
405    }
406
407    /// Returns the `BidKind` if this is a `BidKind` variant.
408    pub fn into_bid_kind(self) -> Option<BidKind> {
409        match self {
410            StoredValue::BidKind(bid_kind) => Some(bid_kind),
411            _ => None,
412        }
413    }
414
415    /// Returns the `EntryPointValue` if this is a `EntryPointValue` variant.
416    pub fn into_entry_point_value(self) -> Option<EntryPointValue> {
417        match self {
418            StoredValue::EntryPoint(value) => Some(value),
419            _ => None,
420        }
421    }
422
423    /// Returns the type name of the [`StoredValue`] enum variant.
424    ///
425    /// For [`CLValue`] variants it will return the name of the [`CLType`](crate::cl_type::CLType)
426    pub fn type_name(&self) -> String {
427        match self {
428            StoredValue::CLValue(cl_value) => format!("{:?}", cl_value.cl_type()),
429            StoredValue::Account(_) => "Account".to_string(),
430            StoredValue::ContractWasm(_) => "ContractWasm".to_string(),
431            StoredValue::Contract(_) => "Contract".to_string(),
432            StoredValue::ContractPackage(_) => "ContractPackage".to_string(),
433            StoredValue::Transfer(_) => "Transfer".to_string(),
434            StoredValue::DeployInfo(_) => "DeployInfo".to_string(),
435            StoredValue::EraInfo(_) => "EraInfo".to_string(),
436            StoredValue::Bid(_) => "Bid".to_string(),
437            StoredValue::Withdraw(_) => "Withdraw".to_string(),
438            StoredValue::Unbonding(_) => "Unbonding".to_string(),
439            StoredValue::AddressableEntity(_) => "AddressableEntity".to_string(),
440            StoredValue::BidKind(_) => "BidKind".to_string(),
441            StoredValue::ByteCode(_) => "ByteCode".to_string(),
442            StoredValue::SmartContract(_) => "SmartContract".to_string(),
443            StoredValue::MessageTopic(_) => "MessageTopic".to_string(),
444            StoredValue::Message(_) => "Message".to_string(),
445            StoredValue::NamedKey(_) => "NamedKey".to_string(),
446            StoredValue::Prepayment(_) => "Prepayment".to_string(),
447            StoredValue::EntryPoint(_) => "EntryPoint".to_string(),
448            StoredValue::RawBytes(_) => "RawBytes".to_string(),
449        }
450    }
451
452    /// Returns the tag of the `StoredValue`.
453    pub fn tag(&self) -> StoredValueTag {
454        match self {
455            StoredValue::CLValue(_) => StoredValueTag::CLValue,
456            StoredValue::Account(_) => StoredValueTag::Account,
457            StoredValue::ContractWasm(_) => StoredValueTag::ContractWasm,
458            StoredValue::ContractPackage(_) => StoredValueTag::ContractPackage,
459            StoredValue::Contract(_) => StoredValueTag::Contract,
460            StoredValue::Transfer(_) => StoredValueTag::Transfer,
461            StoredValue::DeployInfo(_) => StoredValueTag::DeployInfo,
462            StoredValue::EraInfo(_) => StoredValueTag::EraInfo,
463            StoredValue::Bid(_) => StoredValueTag::Bid,
464            StoredValue::Withdraw(_) => StoredValueTag::Withdraw,
465            StoredValue::Unbonding(_) => StoredValueTag::Unbonding,
466            StoredValue::AddressableEntity(_) => StoredValueTag::AddressableEntity,
467            StoredValue::BidKind(_) => StoredValueTag::BidKind,
468            StoredValue::SmartContract(_) => StoredValueTag::Package,
469            StoredValue::ByteCode(_) => StoredValueTag::ByteCode,
470            StoredValue::MessageTopic(_) => StoredValueTag::MessageTopic,
471            StoredValue::Message(_) => StoredValueTag::Message,
472            StoredValue::NamedKey(_) => StoredValueTag::NamedKey,
473            StoredValue::Prepayment(_) => StoredValueTag::Prepayment,
474            StoredValue::EntryPoint(_) => StoredValueTag::EntryPoint,
475            StoredValue::RawBytes(_) => StoredValueTag::RawBytes,
476        }
477    }
478
479    /// Returns the serialized length of the `StoredValue`.
480    pub fn into_byte_code(self) -> Option<ByteCode> {
481        match self {
482            StoredValue::ByteCode(byte_code) => Some(byte_code),
483            _ => None,
484        }
485    }
486
487    /// Returns the serialized length of the `StoredValue`.
488    pub fn into_named_key(self) -> Option<NamedKeyValue> {
489        match self {
490            StoredValue::NamedKey(named_key_value) => Some(named_key_value),
491            _ => None,
492        }
493    }
494}
495
496impl From<CLValue> for StoredValue {
497    fn from(value: CLValue) -> StoredValue {
498        StoredValue::CLValue(value)
499    }
500}
501
502impl From<Account> for StoredValue {
503    fn from(value: Account) -> StoredValue {
504        StoredValue::Account(value)
505    }
506}
507
508impl From<ContractWasm> for StoredValue {
509    fn from(value: ContractWasm) -> Self {
510        StoredValue::ContractWasm(value)
511    }
512}
513
514impl From<ContractPackage> for StoredValue {
515    fn from(value: ContractPackage) -> Self {
516        StoredValue::ContractPackage(value)
517    }
518}
519
520impl From<Contract> for StoredValue {
521    fn from(value: Contract) -> Self {
522        StoredValue::Contract(value)
523    }
524}
525
526impl From<AddressableEntity> for StoredValue {
527    fn from(value: AddressableEntity) -> StoredValue {
528        StoredValue::AddressableEntity(value)
529    }
530}
531
532impl From<Package> for StoredValue {
533    fn from(value: Package) -> StoredValue {
534        StoredValue::SmartContract(value)
535    }
536}
537
538impl From<Bid> for StoredValue {
539    fn from(bid: Bid) -> StoredValue {
540        StoredValue::Bid(Box::new(bid))
541    }
542}
543
544impl From<BidKind> for StoredValue {
545    fn from(bid_kind: BidKind) -> StoredValue {
546        StoredValue::BidKind(bid_kind)
547    }
548}
549
550impl From<ByteCode> for StoredValue {
551    fn from(value: ByteCode) -> StoredValue {
552        StoredValue::ByteCode(value)
553    }
554}
555
556impl From<EntryPointValue> for StoredValue {
557    fn from(value: EntryPointValue) -> Self {
558        StoredValue::EntryPoint(value)
559    }
560}
561
562impl TryFrom<StoredValue> for CLValue {
563    type Error = TypeMismatch;
564
565    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
566        let type_name = stored_value.type_name();
567        match stored_value {
568            StoredValue::CLValue(cl_value) => Ok(cl_value),
569            StoredValue::BidKind(bid_kind) => Ok(CLValue::from_t(bid_kind)
570                .map_err(|_| TypeMismatch::new("BidKind".to_string(), type_name))?),
571            StoredValue::ContractPackage(contract_package) => Ok(CLValue::from_t(contract_package)
572                .map_err(|_error| TypeMismatch::new("ContractPackage".to_string(), type_name))?),
573            _ => Err(TypeMismatch::new("StoredValue".to_string(), type_name)),
574        }
575    }
576}
577
578impl TryFrom<StoredValue> for Account {
579    type Error = TypeMismatch;
580
581    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
582        match stored_value {
583            StoredValue::Account(account) => Ok(account),
584            _ => Err(TypeMismatch::new(
585                "Account".to_string(),
586                stored_value.type_name(),
587            )),
588        }
589    }
590}
591
592impl TryFrom<StoredValue> for ContractWasm {
593    type Error = TypeMismatch;
594
595    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
596        match stored_value {
597            StoredValue::ContractWasm(contract_wasm) => Ok(contract_wasm),
598            _ => Err(TypeMismatch::new(
599                "ContractWasm".to_string(),
600                stored_value.type_name(),
601            )),
602        }
603    }
604}
605
606impl TryFrom<StoredValue> for ByteCode {
607    type Error = TypeMismatch;
608
609    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
610        match stored_value {
611            StoredValue::ByteCode(byte_code) => Ok(byte_code),
612            _ => Err(TypeMismatch::new(
613                "ByteCode".to_string(),
614                stored_value.type_name(),
615            )),
616        }
617    }
618}
619
620impl TryFrom<StoredValue> for ContractPackage {
621    type Error = TypeMismatch;
622
623    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
624        match value {
625            StoredValue::ContractPackage(contract_package) => Ok(contract_package),
626            _ => Err(TypeMismatch::new(
627                "ContractPackage".to_string(),
628                value.type_name(),
629            )),
630        }
631    }
632}
633
634impl TryFrom<StoredValue> for Contract {
635    type Error = TypeMismatch;
636
637    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
638        match stored_value {
639            StoredValue::Contract(contract) => Ok(contract),
640            _ => Err(TypeMismatch::new(
641                "Contract".to_string(),
642                stored_value.type_name(),
643            )),
644        }
645    }
646}
647
648impl TryFrom<StoredValue> for Package {
649    type Error = TypeMismatch;
650
651    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
652        match stored_value {
653            StoredValue::SmartContract(contract_package) => Ok(contract_package),
654            StoredValue::ContractPackage(contract_package) => Ok(contract_package.into()),
655            _ => Err(TypeMismatch::new(
656                "ContractPackage".to_string(),
657                stored_value.type_name(),
658            )),
659        }
660    }
661}
662
663impl TryFrom<StoredValue> for AddressableEntity {
664    type Error = TypeMismatch;
665
666    fn try_from(stored_value: StoredValue) -> Result<Self, Self::Error> {
667        match stored_value {
668            StoredValue::AddressableEntity(contract) => Ok(contract),
669            _ => Err(TypeMismatch::new(
670                "AddressableEntity".to_string(),
671                stored_value.type_name(),
672            )),
673        }
674    }
675}
676
677impl TryFrom<StoredValue> for TransferV1 {
678    type Error = TypeMismatch;
679
680    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
681        match value {
682            StoredValue::Transfer(transfer_v1) => Ok(transfer_v1),
683            _ => Err(TypeMismatch::new("Transfer".to_string(), value.type_name())),
684        }
685    }
686}
687
688impl TryFrom<StoredValue> for DeployInfo {
689    type Error = TypeMismatch;
690
691    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
692        match value {
693            StoredValue::DeployInfo(deploy_info) => Ok(deploy_info),
694            _ => Err(TypeMismatch::new(
695                "DeployInfo".to_string(),
696                value.type_name(),
697            )),
698        }
699    }
700}
701
702impl TryFrom<StoredValue> for EraInfo {
703    type Error = TypeMismatch;
704
705    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
706        match value {
707            StoredValue::EraInfo(era_info) => Ok(era_info),
708            _ => Err(TypeMismatch::new("EraInfo".to_string(), value.type_name())),
709        }
710    }
711}
712
713impl TryFrom<StoredValue> for Bid {
714    type Error = TypeMismatch;
715
716    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
717        match value {
718            StoredValue::Bid(bid) => Ok(*bid),
719            _ => Err(TypeMismatch::new("Bid".to_string(), value.type_name())),
720        }
721    }
722}
723
724impl TryFrom<StoredValue> for BidKind {
725    type Error = TypeMismatch;
726
727    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
728        match value {
729            StoredValue::BidKind(bid_kind) => Ok(bid_kind),
730            _ => Err(TypeMismatch::new("BidKind".to_string(), value.type_name())),
731        }
732    }
733}
734
735impl TryFrom<StoredValue> for NamedKeyValue {
736    type Error = TypeMismatch;
737
738    fn try_from(value: StoredValue) -> Result<Self, Self::Error> {
739        match value {
740            StoredValue::NamedKey(named_key_value) => Ok(named_key_value),
741            _ => Err(TypeMismatch::new(
742                "NamedKeyValue".to_string(),
743                value.type_name(),
744            )),
745        }
746    }
747}
748
749impl ToBytes for StoredValue {
750    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
751        let mut buffer = bytesrepr::allocate_buffer(self)?;
752        self.write_bytes(&mut buffer)?;
753        Ok(buffer)
754    }
755
756    fn serialized_length(&self) -> usize {
757        U8_SERIALIZED_LENGTH
758            + match self {
759                StoredValue::CLValue(cl_value) => cl_value.serialized_length(),
760                StoredValue::Account(account) => account.serialized_length(),
761                StoredValue::ContractWasm(contract_wasm) => contract_wasm.serialized_length(),
762                StoredValue::Contract(contract_header) => contract_header.serialized_length(),
763                StoredValue::ContractPackage(contract_package) => {
764                    contract_package.serialized_length()
765                }
766                StoredValue::Transfer(transfer_v1) => transfer_v1.serialized_length(),
767                StoredValue::DeployInfo(deploy_info) => deploy_info.serialized_length(),
768                StoredValue::EraInfo(era_info) => era_info.serialized_length(),
769                StoredValue::Bid(bid) => bid.serialized_length(),
770                StoredValue::Withdraw(withdraw_purses) => withdraw_purses.serialized_length(),
771                StoredValue::Unbonding(unbonding_purses) => unbonding_purses.serialized_length(),
772                StoredValue::AddressableEntity(entity) => entity.serialized_length(),
773                StoredValue::BidKind(bid_kind) => bid_kind.serialized_length(),
774                StoredValue::SmartContract(package) => package.serialized_length(),
775                StoredValue::ByteCode(byte_code) => byte_code.serialized_length(),
776                StoredValue::MessageTopic(message_topic_summary) => {
777                    message_topic_summary.serialized_length()
778                }
779                StoredValue::Message(message_digest) => message_digest.serialized_length(),
780                StoredValue::NamedKey(named_key_value) => named_key_value.serialized_length(),
781                StoredValue::Prepayment(prepayment_kind) => prepayment_kind.serialized_length(),
782                StoredValue::EntryPoint(entry_point_value) => entry_point_value.serialized_length(),
783                StoredValue::RawBytes(bytes) => bytes.serialized_length(),
784            }
785    }
786
787    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
788        writer.push(self.tag() as u8);
789        match self {
790            StoredValue::CLValue(cl_value) => cl_value.write_bytes(writer),
791            StoredValue::Account(account) => account.write_bytes(writer),
792            StoredValue::ContractWasm(contract_wasm) => contract_wasm.write_bytes(writer),
793            StoredValue::Contract(contract_header) => contract_header.write_bytes(writer),
794            StoredValue::ContractPackage(contract_package) => contract_package.write_bytes(writer),
795            StoredValue::Transfer(transfer_v1) => transfer_v1.write_bytes(writer),
796            StoredValue::DeployInfo(deploy_info) => deploy_info.write_bytes(writer),
797            StoredValue::EraInfo(era_info) => era_info.write_bytes(writer),
798            StoredValue::Bid(bid) => bid.write_bytes(writer),
799            StoredValue::Withdraw(unbonding_purses) => unbonding_purses.write_bytes(writer),
800            StoredValue::Unbonding(unbonding_purses) => unbonding_purses.write_bytes(writer),
801            StoredValue::AddressableEntity(entity) => entity.write_bytes(writer),
802            StoredValue::BidKind(bid_kind) => bid_kind.write_bytes(writer),
803            StoredValue::SmartContract(package) => package.write_bytes(writer),
804            StoredValue::ByteCode(byte_code) => byte_code.write_bytes(writer),
805            StoredValue::MessageTopic(message_topic_summary) => {
806                message_topic_summary.write_bytes(writer)
807            }
808            StoredValue::Message(message_digest) => message_digest.write_bytes(writer),
809            StoredValue::NamedKey(named_key_value) => named_key_value.write_bytes(writer),
810            StoredValue::Prepayment(prepayment_kind) => prepayment_kind.write_bytes(writer),
811            StoredValue::EntryPoint(entry_point_value) => entry_point_value.write_bytes(writer),
812            StoredValue::RawBytes(bytes) => bytes.write_bytes(writer),
813        }
814    }
815}
816
817impl FromBytes for StoredValue {
818    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
819        let (tag, remainder) = u8::from_bytes(bytes)?;
820        match tag {
821            tag if tag == StoredValueTag::CLValue as u8 => CLValue::from_bytes(remainder)
822                .map(|(cl_value, remainder)| (StoredValue::CLValue(cl_value), remainder)),
823            tag if tag == StoredValueTag::Account as u8 => Account::from_bytes(remainder)
824                .map(|(account, remainder)| (StoredValue::Account(account), remainder)),
825            tag if tag == StoredValueTag::ContractWasm as u8 => ContractWasm::from_bytes(remainder)
826                .map(|(contract_wasm, remainder)| {
827                    (StoredValue::ContractWasm(contract_wasm), remainder)
828                }),
829            tag if tag == StoredValueTag::ContractPackage as u8 => {
830                ContractPackage::from_bytes(remainder).map(|(contract_package, remainder)| {
831                    (StoredValue::ContractPackage(contract_package), remainder)
832                })
833            }
834            tag if tag == StoredValueTag::Contract as u8 => Contract::from_bytes(remainder)
835                .map(|(contract, remainder)| (StoredValue::Contract(contract), remainder)),
836            tag if tag == StoredValueTag::Transfer as u8 => TransferV1::from_bytes(remainder)
837                .map(|(transfer_v1, remainder)| (StoredValue::Transfer(transfer_v1), remainder)),
838            tag if tag == StoredValueTag::DeployInfo as u8 => DeployInfo::from_bytes(remainder)
839                .map(|(deploy_info, remainder)| (StoredValue::DeployInfo(deploy_info), remainder)),
840            tag if tag == StoredValueTag::EraInfo as u8 => EraInfo::from_bytes(remainder)
841                .map(|(deploy_info, remainder)| (StoredValue::EraInfo(deploy_info), remainder)),
842            tag if tag == StoredValueTag::Bid as u8 => Bid::from_bytes(remainder)
843                .map(|(bid, remainder)| (StoredValue::Bid(Box::new(bid)), remainder)),
844            tag if tag == StoredValueTag::BidKind as u8 => BidKind::from_bytes(remainder)
845                .map(|(bid_kind, remainder)| (StoredValue::BidKind(bid_kind), remainder)),
846            tag if tag == StoredValueTag::Withdraw as u8 => {
847                Vec::<WithdrawPurse>::from_bytes(remainder).map(|(withdraw_purses, remainder)| {
848                    (StoredValue::Withdraw(withdraw_purses), remainder)
849                })
850            }
851            tag if tag == StoredValueTag::Unbonding as u8 => {
852                Vec::<UnbondingPurse>::from_bytes(remainder).map(|(unbonding_purses, remainder)| {
853                    (StoredValue::Unbonding(unbonding_purses), remainder)
854                })
855            }
856            tag if tag == StoredValueTag::AddressableEntity as u8 => {
857                AddressableEntity::from_bytes(remainder)
858                    .map(|(entity, remainder)| (StoredValue::AddressableEntity(entity), remainder))
859            }
860            tag if tag == StoredValueTag::Package as u8 => Package::from_bytes(remainder)
861                .map(|(package, remainder)| (StoredValue::SmartContract(package), remainder)),
862            tag if tag == StoredValueTag::ByteCode as u8 => ByteCode::from_bytes(remainder)
863                .map(|(byte_code, remainder)| (StoredValue::ByteCode(byte_code), remainder)),
864            tag if tag == StoredValueTag::MessageTopic as u8 => {
865                MessageTopicSummary::from_bytes(remainder).map(|(message_summary, remainder)| {
866                    (StoredValue::MessageTopic(message_summary), remainder)
867                })
868            }
869            tag if tag == StoredValueTag::Message as u8 => MessageChecksum::from_bytes(remainder)
870                .map(|(checksum, remainder)| (StoredValue::Message(checksum), remainder)),
871            tag if tag == StoredValueTag::NamedKey as u8 => NamedKeyValue::from_bytes(remainder)
872                .map(|(named_key_value, remainder)| {
873                    (StoredValue::NamedKey(named_key_value), remainder)
874                }),
875            tag if tag == StoredValueTag::EntryPoint as u8 => {
876                EntryPointValue::from_bytes(remainder).map(|(entry_point, remainder)| {
877                    (StoredValue::EntryPoint(entry_point), remainder)
878                })
879            }
880            tag if tag == StoredValueTag::RawBytes as u8 => {
881                let (bytes, remainder) = Bytes::from_bytes(remainder)?;
882                Ok((StoredValue::RawBytes(bytes.into()), remainder))
883            }
884            _ => Err(Error::Formatting),
885        }
886    }
887}
888
889pub mod serde_helpers {
890    use core::fmt::Display;
891
892    use crate::serde_helpers::contract::HumanReadableContract;
893
894    use super::*;
895
896    #[derive(Serialize)]
897    #[cfg_attr(
898        feature = "json-schema",
899        derive(JsonSchema),
900        schemars(
901            rename = "StoredValue",
902            description = "A value stored in Global State."
903        )
904    )]
905    pub(crate) enum HumanReadableSerHelper<'a> {
906        CLValue(&'a CLValue),
907        Account(&'a Account),
908        ContractWasm(&'a ContractWasm),
909        Contract(HumanReadableContract),
910        ContractPackage(&'a ContractPackage),
911        Transfer(&'a TransferV1),
912        DeployInfo(&'a DeployInfo),
913        EraInfo(&'a EraInfo),
914        Bid(&'a Bid),
915        Withdraw(&'a Vec<WithdrawPurse>),
916        Unbonding(&'a Vec<UnbondingPurse>),
917        AddressableEntity(&'a AddressableEntity),
918        BidKind(&'a BidKind),
919        SmartContract(&'a Package),
920        ByteCode(&'a ByteCode),
921        MessageTopic(&'a MessageTopicSummary),
922        Message(&'a MessageChecksum),
923        NamedKey(&'a NamedKeyValue),
924        Prepayment(&'a PrepaymentKind),
925        EntryPoint(&'a EntryPointValue),
926        RawBytes(Bytes),
927    }
928
929    /// A value stored in Global State.
930    #[derive(Deserialize)]
931    #[cfg_attr(
932        feature = "json-schema",
933        derive(JsonSchema),
934        schemars(
935            rename = "StoredValue",
936            description = "A value stored in Global State."
937        )
938    )]
939    pub(crate) enum HumanReadableDeserHelper {
940        /// A CLValue.
941        CLValue(CLValue),
942        /// An account.
943        Account(Account),
944        /// Contract wasm.
945        ContractWasm(ContractWasm),
946        /// A contract.
947        Contract(HumanReadableContract),
948        /// A contract package.
949        ContractPackage(ContractPackage),
950        /// A version 1 transfer.
951        Transfer(TransferV1),
952        /// Info about a deploy.
953        DeployInfo(DeployInfo),
954        /// Info about an era.
955        EraInfo(EraInfo),
956        /// Variant that stores [`Bid`].
957        Bid(Box<Bid>),
958        /// Variant that stores withdraw information.
959        Withdraw(Vec<WithdrawPurse>),
960        /// Unbonding information.
961        Unbonding(Vec<UnbondingPurse>),
962        /// An `AddressableEntity`.
963        AddressableEntity(AddressableEntity),
964        /// Variant that stores [`BidKind`].
965        BidKind(BidKind),
966        /// A smart contract `Package`.
967        SmartContract(Package),
968        /// A record of byte code.
969        ByteCode(ByteCode),
970        /// Variant that stores a message topic.
971        MessageTopic(MessageTopicSummary),
972        /// Variant that stores a message digest.
973        Message(MessageChecksum),
974        /// A NamedKey record.
975        NamedKey(NamedKeyValue),
976        /// A prepayment record.
977        EntryPoint(EntryPointValue),
978        /// An entrypoint record.
979        Prepayment(PrepaymentKind),
980        /// Raw bytes. Similar to a [`crate::StoredValue::CLValue`] but does not incur overhead of
981        /// a [`crate::CLValue`] and [`crate::CLType`].
982        RawBytes(Bytes),
983    }
984
985    impl<'a> From<&'a StoredValue> for HumanReadableSerHelper<'a> {
986        fn from(stored_value: &'a StoredValue) -> Self {
987            match stored_value {
988                StoredValue::CLValue(payload) => HumanReadableSerHelper::CLValue(payload),
989                StoredValue::Account(payload) => HumanReadableSerHelper::Account(payload),
990                StoredValue::ContractWasm(payload) => HumanReadableSerHelper::ContractWasm(payload),
991                StoredValue::Contract(payload) => HumanReadableSerHelper::Contract(payload.into()),
992                StoredValue::ContractPackage(payload) => {
993                    HumanReadableSerHelper::ContractPackage(payload)
994                }
995                StoredValue::Transfer(payload) => HumanReadableSerHelper::Transfer(payload),
996                StoredValue::DeployInfo(payload) => HumanReadableSerHelper::DeployInfo(payload),
997                StoredValue::EraInfo(payload) => HumanReadableSerHelper::EraInfo(payload),
998                StoredValue::Bid(payload) => HumanReadableSerHelper::Bid(payload),
999                StoredValue::Withdraw(payload) => HumanReadableSerHelper::Withdraw(payload),
1000                StoredValue::Unbonding(payload) => HumanReadableSerHelper::Unbonding(payload),
1001                StoredValue::AddressableEntity(payload) => {
1002                    HumanReadableSerHelper::AddressableEntity(payload)
1003                }
1004                StoredValue::BidKind(payload) => HumanReadableSerHelper::BidKind(payload),
1005                StoredValue::SmartContract(payload) => {
1006                    HumanReadableSerHelper::SmartContract(payload)
1007                }
1008                StoredValue::ByteCode(payload) => HumanReadableSerHelper::ByteCode(payload),
1009                StoredValue::MessageTopic(message_topic_summary) => {
1010                    HumanReadableSerHelper::MessageTopic(message_topic_summary)
1011                }
1012                StoredValue::Message(message_digest) => {
1013                    HumanReadableSerHelper::Message(message_digest)
1014                }
1015                StoredValue::NamedKey(payload) => HumanReadableSerHelper::NamedKey(payload),
1016                StoredValue::Prepayment(payload) => HumanReadableSerHelper::Prepayment(payload),
1017                StoredValue::EntryPoint(payload) => HumanReadableSerHelper::EntryPoint(payload),
1018                StoredValue::RawBytes(bytes) => {
1019                    HumanReadableSerHelper::RawBytes(bytes.as_slice().into())
1020                }
1021            }
1022        }
1023    }
1024
1025    /// Parsing error when deserializing StoredValue.
1026    #[derive(Debug, Clone)]
1027    pub enum StoredValueDeserializationError {
1028        /// Contract not deserializable.
1029        CouldNotDeserializeContract(String),
1030    }
1031
1032    impl Display for StoredValueDeserializationError {
1033        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1034            match self {
1035                StoredValueDeserializationError::CouldNotDeserializeContract(reason) => {
1036                    write!(
1037                        f,
1038                        "Could not deserialize StoredValue::Contract. Reason: {reason}"
1039                    )
1040                }
1041            }
1042        }
1043    }
1044
1045    impl TryFrom<HumanReadableDeserHelper> for StoredValue {
1046        type Error = StoredValueDeserializationError;
1047        fn try_from(helper: HumanReadableDeserHelper) -> Result<Self, Self::Error> {
1048            Ok(match helper {
1049                HumanReadableDeserHelper::CLValue(payload) => StoredValue::CLValue(payload),
1050                HumanReadableDeserHelper::Account(payload) => StoredValue::Account(payload),
1051                HumanReadableDeserHelper::ContractWasm(payload) => {
1052                    StoredValue::ContractWasm(payload)
1053                }
1054                HumanReadableDeserHelper::Contract(payload) => {
1055                    StoredValue::Contract(Contract::try_from(payload).map_err(|e| {
1056                        StoredValueDeserializationError::CouldNotDeserializeContract(e.to_string())
1057                    })?)
1058                }
1059                HumanReadableDeserHelper::ContractPackage(payload) => {
1060                    StoredValue::ContractPackage(payload)
1061                }
1062                HumanReadableDeserHelper::Transfer(payload) => StoredValue::Transfer(payload),
1063                HumanReadableDeserHelper::DeployInfo(payload) => StoredValue::DeployInfo(payload),
1064                HumanReadableDeserHelper::EraInfo(payload) => StoredValue::EraInfo(payload),
1065                HumanReadableDeserHelper::Bid(bid) => StoredValue::Bid(bid),
1066                HumanReadableDeserHelper::Withdraw(payload) => StoredValue::Withdraw(payload),
1067                HumanReadableDeserHelper::Unbonding(payload) => StoredValue::Unbonding(payload),
1068                HumanReadableDeserHelper::AddressableEntity(payload) => {
1069                    StoredValue::AddressableEntity(payload)
1070                }
1071                HumanReadableDeserHelper::BidKind(payload) => StoredValue::BidKind(payload),
1072                HumanReadableDeserHelper::ByteCode(payload) => StoredValue::ByteCode(payload),
1073                HumanReadableDeserHelper::SmartContract(payload) => {
1074                    StoredValue::SmartContract(payload)
1075                }
1076                HumanReadableDeserHelper::MessageTopic(message_topic_summary) => {
1077                    StoredValue::MessageTopic(message_topic_summary)
1078                }
1079                HumanReadableDeserHelper::Message(message_digest) => {
1080                    StoredValue::Message(message_digest)
1081                }
1082                HumanReadableDeserHelper::NamedKey(payload) => StoredValue::NamedKey(payload),
1083                HumanReadableDeserHelper::EntryPoint(payload) => StoredValue::EntryPoint(payload),
1084                HumanReadableDeserHelper::RawBytes(bytes) => StoredValue::RawBytes(bytes.into()),
1085                HumanReadableDeserHelper::Prepayment(prepayment_kind) => {
1086                    StoredValue::Prepayment(prepayment_kind)
1087                }
1088            })
1089        }
1090    }
1091}
1092
1093impl Serialize for StoredValue {
1094    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1095        if serializer.is_human_readable() {
1096            serde_helpers::HumanReadableSerHelper::from(self).serialize(serializer)
1097        } else {
1098            let bytes = self
1099                .to_bytes()
1100                .map_err(|error| ser::Error::custom(format!("{:?}", error)))?;
1101            ByteBuf::from(bytes).serialize(serializer)
1102        }
1103    }
1104}
1105
1106impl<'de> Deserialize<'de> for StoredValue {
1107    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
1108        if deserializer.is_human_readable() {
1109            let json_helper = serde_helpers::HumanReadableDeserHelper::deserialize(deserializer)?;
1110            StoredValue::try_from(json_helper).map_err(de::Error::custom)
1111        } else {
1112            let bytes = ByteBuf::deserialize(deserializer)?.into_vec();
1113            bytesrepr::deserialize::<StoredValue>(bytes)
1114                .map_err(|error| de::Error::custom(format!("{:?}", error)))
1115        }
1116    }
1117}
1118
1119#[cfg(test)]
1120mod tests {
1121    use crate::{bytesrepr, gens, StoredValue};
1122    use proptest::proptest;
1123    use serde_json::Value;
1124
1125    const STORED_VALUE_CONTRACT_RAW: &str = r#"{
1126    "Contract": {
1127            "contract_package_hash": "contract-package-e26c7f95890f99b4d476609649939910e636e175c428add9b403ebe597673005",
1128            "contract_wasm_hash": "contract-wasm-8447a228c6055df42fcedb18804786abcab0e7aed00e94ad0fc0a34cd09509fb",
1129            "named_keys": [
1130                {
1131                    "name": "count_v2.0",
1132                    "key": "uref-53834a8313fa5eda357a75ef8eb017e1ed30bc64e6dbaa81a41abd0ffd761586-007"
1133                }
1134            ],
1135            "entry_points": [
1136                {
1137                    "name": "counter_get",
1138                    "args": [],
1139                    "ret": "I32",
1140                    "access": "Public",
1141                    "entry_point_type": "Caller"
1142                },
1143                {
1144                    "name": "counter_inc",
1145                    "args": [],
1146                    "ret": "Unit",
1147                    "access": "Public",
1148                    "entry_point_type": "Called"
1149                },
1150                {
1151                    "name": "counter_zero",
1152                    "args": [],
1153                    "ret": "Unit",
1154                    "access": "Public",
1155                    "entry_point_type": "Factory"
1156                }
1157                
1158            ],
1159            "protocol_version": "2.0.0"
1160        }
1161}
1162    "#;
1163
1164    const JSON_CONTRACT_NON_UNIQUE_ENTRYPOINT_NAMES_RAW: &str = r#"{
1165        "Contract": {
1166                "contract_package_hash": "contract-package-e26c7f95890f99b4d476609649939910e636e175c428add9b403ebe597673005",
1167                "contract_wasm_hash": "contract-wasm-8447a228c6055df42fcedb18804786abcab0e7aed00e94ad0fc0a34cd09509fb",
1168                "named_keys": [
1169                    {
1170                        "name": "count_v2.0",
1171                        "key": "uref-53834a8313fa5eda357a75ef8eb017e1ed30bc64e6dbaa81a41abd0ffd761586-007"
1172                    }
1173                ],
1174                "entry_points": [
1175                    {
1176                        "name": "counter_get",
1177                        "args": [],
1178                        "ret": "I32",
1179                        "access": "Public",
1180                        "entry_point_type": "Caller"
1181                    },
1182                    {
1183                        "name": "counter_get",
1184                        "args": [],
1185                        "ret": "Unit",
1186                        "access": "Public",
1187                        "entry_point_type": "Called"
1188                    },
1189                    {
1190                        "name": "counter_inc",
1191                        "args": [],
1192                        "ret": "Unit",
1193                        "access": "Public",
1194                        "entry_point_type": "Factory"
1195                    }
1196                ],
1197                "protocol_version": "2.0.0"
1198            }
1199    }
1200        "#;
1201
1202    const STORED_VALUE_CONTRACT_PACKAGE_RAW: &str = r#"
1203    {
1204        "ContractPackage": {
1205          "access_key": "uref-024d69e50a458f337817d3d11ba95bdbdd6258ba8f2dc980644c9efdbd64945d-007",
1206          "versions": [
1207            {
1208              "protocol_version_major": 1,
1209              "contract_version": 1,
1210              "contract_hash": "contract-1b301b49505ec5eaec1787686c54818bd60836b9301cce3f5c0237560e5a4bfd"
1211            }
1212          ],
1213          "disabled_versions": [],
1214          "groups": [],
1215          "lock_status": "Unlocked"
1216        }
1217    }"#;
1218
1219    const INCORRECT_STORED_VALUE_CONTRACT_PACKAGE_RAW: &str = r#"
1220    {
1221        "ContractPackage": {
1222          "access_key": "uref-024d69e50a458f337817d3d11ba95bdbdd6258ba8f2dc980644c9efdbd64945d-007",
1223          "versions": [
1224            {
1225              "protocol_version_major": 1,
1226              "contract_version": 1,
1227              "contract_hash": "contract-1b301b49505ec5eaec1787686c54818bd60836b9301cce3f5c0237560e5a4bfd"
1228            },
1229            {
1230              "protocol_version_major": 1,
1231              "contract_version": 1,
1232              "contract_hash": "contract-1b301b49505ec5eaec1787686c54818bd60836b9301cce3f5c0237560e5a4bfe"
1233            }
1234          ],
1235          "disabled_versions": [],
1236          "groups": [],
1237          "lock_status": "Unlocked"
1238        }
1239    }
1240    "#;
1241
1242    #[test]
1243    fn cannot_deserialize_contract_with_non_unique_entry_point_names() {
1244        let res =
1245            serde_json::from_str::<StoredValue>(JSON_CONTRACT_NON_UNIQUE_ENTRYPOINT_NAMES_RAW);
1246        assert!(res.is_err());
1247        assert_eq!(
1248            res.err().unwrap().to_string(),
1249            "Could not deserialize StoredValue::Contract. Reason: Non unique `entry_points.name`"
1250        )
1251    }
1252
1253    #[test]
1254    fn contract_stored_value_serializes_entry_points_to_flat_array() {
1255        let value_from_raw_json = serde_json::from_str::<Value>(STORED_VALUE_CONTRACT_RAW).unwrap();
1256        let deserialized = serde_json::from_str::<StoredValue>(STORED_VALUE_CONTRACT_RAW).unwrap();
1257        let roundtrip_value = serde_json::to_value(&deserialized).unwrap();
1258        assert_eq!(value_from_raw_json, roundtrip_value);
1259    }
1260
1261    #[test]
1262    fn contract_package_stored_value_serializes_versions_to_flat_array() {
1263        let value_from_raw_json =
1264            serde_json::from_str::<Value>(STORED_VALUE_CONTRACT_PACKAGE_RAW).unwrap();
1265        let deserialized =
1266            serde_json::from_str::<StoredValue>(STORED_VALUE_CONTRACT_PACKAGE_RAW).unwrap();
1267        let roundtrip_value = serde_json::to_value(&deserialized).unwrap();
1268        assert_eq!(value_from_raw_json, roundtrip_value);
1269    }
1270
1271    #[test]
1272    fn contract_package_stored_value_should_fail_on_duplicate_keys() {
1273        let deserialization_res =
1274            serde_json::from_str::<StoredValue>(INCORRECT_STORED_VALUE_CONTRACT_PACKAGE_RAW);
1275        assert!(deserialization_res.is_err());
1276        assert!(deserialization_res
1277            .unwrap_err()
1278            .to_string()
1279            .contains("duplicate contract version: ContractVersionKey(1, 1)"));
1280    }
1281
1282    #[test]
1283    fn json_serialization_of_raw_bytes() {
1284        let stored_value = StoredValue::RawBytes(vec![1, 2, 3, 4]);
1285        assert_eq!(
1286            serde_json::to_string(&stored_value).unwrap(),
1287            r#"{"RawBytes":"01020304"}"#
1288        );
1289    }
1290
1291    proptest! {
1292
1293        #[test]
1294        fn json_serialization_roundtrip(v in gens::stored_value_arb()) {
1295            let json_str = serde_json::to_string(&v).unwrap();
1296            let deserialized = serde_json::from_str::<StoredValue>(&json_str).unwrap();
1297            assert_eq!(v, deserialized);
1298        }
1299
1300        #[test]
1301        fn serialization_roundtrip(v in gens::stored_value_arb()) {
1302            bytesrepr::test_serialization_roundtrip(&v);
1303        }
1304    }
1305}