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#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
37#[repr(u8)]
38pub enum StoredValueTag {
39 CLValue = 0,
41 Account = 1,
43 ContractWasm = 2,
45 Contract = 3,
47 ContractPackage = 4,
49 Transfer = 5,
51 DeployInfo = 6,
53 EraInfo = 7,
55 Bid = 8,
57 Withdraw = 9,
59 Unbonding = 10,
61 BidKind = 11,
63 Package = 12,
65 AddressableEntity = 13,
67 ByteCode = 14,
69 MessageTopic = 15,
71 Message = 16,
73 NamedKey = 17,
75 Prepayment = 18,
77 EntryPoint = 19,
79 RawBytes = 20,
81}
82
83#[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 CLValue(CLValue),
95 Account(Account),
97 ContractWasm(ContractWasm),
99 Contract(Contract),
101 ContractPackage(ContractPackage),
103 Transfer(TransferV1),
105 DeployInfo(DeployInfo),
107 EraInfo(EraInfo),
109 Bid(Box<Bid>),
111 Withdraw(Vec<WithdrawPurse>),
113 Unbonding(Vec<UnbondingPurse>),
115 AddressableEntity(AddressableEntity),
117 BidKind(BidKind),
119 SmartContract(Package),
121 ByteCode(ByteCode),
123 MessageTopic(MessageTopicSummary),
125 Message(MessageChecksum),
127 NamedKey(NamedKeyValue),
129 Prepayment(PrepaymentKind),
131 EntryPoint(EntryPointValue),
133 RawBytes(#[cfg_attr(feature = "json-schema", schemars(with = "String"))] Vec<u8>),
136}
137
138impl StoredValue {
139 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 pub fn as_account(&self) -> Option<&Account> {
149 match self {
150 StoredValue::Account(account) => Some(account),
151 _ => None,
152 }
153 }
154
155 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 pub fn as_contract(&self) -> Option<&Contract> {
172 match self {
173 StoredValue::Contract(contract) => Some(contract),
174 _ => None,
175 }
176 }
177
178 pub fn as_package(&self) -> Option<&Package> {
180 match self {
181 StoredValue::SmartContract(package) => Some(package),
182 _ => None,
183 }
184 }
185
186 pub fn as_contract_package(&self) -> Option<&ContractPackage> {
188 match self {
189 StoredValue::ContractPackage(package) => Some(package),
190 _ => None,
191 }
192 }
193
194 pub fn as_transfer(&self) -> Option<&TransferV1> {
196 match self {
197 StoredValue::Transfer(transfer_v1) => Some(transfer_v1),
198 _ => None,
199 }
200 }
201
202 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 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 pub fn as_bid(&self) -> Option<&Bid> {
220 match self {
221 StoredValue::Bid(bid) => Some(bid),
222 _ => None,
223 }
224 }
225
226 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 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 pub fn as_unbond(&self) -> Option<&Unbond> {
246 match self {
247 StoredValue::BidKind(BidKind::Unbond(unbond)) => Some(unbond),
248 _ => None,
249 }
250 }
251
252 pub fn as_addressable_entity(&self) -> Option<&AddressableEntity> {
255 match self {
256 StoredValue::AddressableEntity(entity) => Some(entity),
257 _ => None,
258 }
259 }
260
261 pub fn as_message_topic_summary(&self) -> Option<&MessageTopicSummary> {
264 match self {
265 StoredValue::MessageTopic(summary) => Some(summary),
266 _ => None,
267 }
268 }
269
270 pub fn as_message_checksum(&self) -> Option<&MessageChecksum> {
273 match self {
274 StoredValue::Message(checksum) => Some(checksum),
275 _ => None,
276 }
277 }
278
279 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 pub fn as_raw_bytes(&self) -> Option<&[u8]> {
289 match self {
290 StoredValue::RawBytes(bytes) => Some(bytes),
291 _ => None,
292 }
293 }
294
295 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 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 pub fn into_account(self) -> Option<Account> {
313 match self {
314 StoredValue::Account(account) => Some(account),
315 _ => None,
316 }
317 }
318
319 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 pub fn into_contract(self) -> Option<Contract> {
329 match self {
330 StoredValue::Contract(contract) => Some(contract),
331 _ => None,
332 }
333 }
334
335 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 pub fn into_package(self) -> Option<Package> {
345 match self {
346 StoredValue::SmartContract(package) => Some(package),
347 _ => None,
348 }
349 }
350
351 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 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 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 pub fn into_bid(self) -> Option<Bid> {
377 match self {
378 StoredValue::Bid(bid) => Some(*bid),
379 _ => None,
380 }
381 }
382
383 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 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 pub fn into_addressable_entity(self) -> Option<AddressableEntity> {
401 match self {
402 StoredValue::AddressableEntity(entity) => Some(entity),
403 _ => None,
404 }
405 }
406
407 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 pub fn into_entry_point_value(self) -> Option<EntryPointValue> {
417 match self {
418 StoredValue::EntryPoint(value) => Some(value),
419 _ => None,
420 }
421 }
422
423 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 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 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 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 #[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 CLValue(CLValue),
942 Account(Account),
944 ContractWasm(ContractWasm),
946 Contract(HumanReadableContract),
948 ContractPackage(ContractPackage),
950 Transfer(TransferV1),
952 DeployInfo(DeployInfo),
954 EraInfo(EraInfo),
956 Bid(Box<Bid>),
958 Withdraw(Vec<WithdrawPurse>),
960 Unbonding(Vec<UnbondingPurse>),
962 AddressableEntity(AddressableEntity),
964 BidKind(BidKind),
966 SmartContract(Package),
968 ByteCode(ByteCode),
970 MessageTopic(MessageTopicSummary),
972 Message(MessageChecksum),
974 NamedKey(NamedKeyValue),
976 EntryPoint(EntryPointValue),
978 Prepayment(PrepaymentKind),
980 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 #[derive(Debug, Clone)]
1027 pub enum StoredValueDeserializationError {
1028 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}