1use std::collections::BTreeMap;
6
7use super::{Address, Digest, Identifier, ObjectId, StructTag};
8
9pub type Version = u64;
10
11#[derive(Clone, Debug, PartialEq, Eq, Hash)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
25#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
26pub struct ObjectReference {
27 pub object_id: ObjectId,
29 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
31 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
32 pub version: Version,
33 pub digest: Digest,
35}
36
37impl ObjectReference {
38 pub fn new(object_id: ObjectId, version: Version, digest: Digest) -> Self {
41 Self {
42 object_id,
43 version,
44 digest,
45 }
46 }
47
48 pub fn object_id(&self) -> &ObjectId {
51 &self.object_id
52 }
53
54 pub fn version(&self) -> Version {
57 self.version
58 }
59
60 pub fn digest(&self) -> &Digest {
63 &self.digest
64 }
65
66 pub fn into_parts(self) -> (ObjectId, Version, Digest) {
68 let Self {
69 object_id,
70 version,
71 digest,
72 } = self;
73
74 (object_id, version, digest)
75 }
76}
77
78#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
93#[cfg_attr(
94 feature = "serde",
95 derive(serde::Serialize, serde::Deserialize),
96 serde(rename_all = "lowercase")
97)]
98#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
99#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
100pub enum Owner {
101 Address(Address),
103 Object(ObjectId),
105 Shared(
107 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
109 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
110 Version,
111 ),
112 Immutable,
114}
115
116impl Owner {
117 crate::def_is!(Immutable);
118
119 crate::def_is_as_into_opt!(Address, Object(ObjectId), Shared(Version));
120}
121
122impl std::fmt::Display for Owner {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 match self {
125 Owner::Address(address) => write!(f, "Address({address})"),
126 Owner::Object(object_id) => write!(f, "Object({object_id})"),
127 Owner::Shared(version) => write!(f, "Shared({version})"),
128 Owner::Immutable => write!(f, "Immutable"),
129 }
130 }
131}
132
133#[derive(Clone, Debug, PartialEq, Eq, Hash)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147#[allow(clippy::large_enum_variant)]
148#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
149pub enum ObjectData {
151 Struct(MoveStruct),
153 Package(MovePackage),
155 }
157
158impl ObjectData {
159 crate::def_is_as_into_opt!(Struct(MoveStruct), Package(MovePackage));
160}
161
162#[derive(Eq, PartialEq, Debug, Clone, Hash)]
176#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
177#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
178pub struct MovePackage {
179 pub id: ObjectId,
181 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
193 pub version: Version,
194 #[cfg_attr(
196 feature = "serde",
197 serde(with = "::serde_with::As::<BTreeMap<::serde_with::Same, ::serde_with::Bytes>>")
198 )]
199 #[cfg_attr(
200 feature = "proptest",
201 strategy(
202 proptest::collection::btree_map(proptest::arbitrary::any::<Identifier>(), proptest::collection::vec(proptest::arbitrary::any::<u8>(), 0..=1024), 0..=5)
203 )
204 )]
205 pub modules: BTreeMap<Identifier, Vec<u8>>,
206 pub type_origin_table: Vec<TypeOrigin>,
209 #[cfg_attr(
212 feature = "proptest",
213 strategy(
214 proptest::collection::btree_map(proptest::arbitrary::any::<ObjectId>(), proptest::arbitrary::any::<UpgradeInfo>(), 0..=5)
215 )
216 )]
217 pub linkage_table: BTreeMap<ObjectId, UpgradeInfo>,
218}
219
220#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
230#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
231#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
232#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
233pub struct TypeOrigin {
234 pub module_name: Identifier,
235 pub struct_name: Identifier,
236 pub package: ObjectId,
237}
238
239#[derive(Eq, PartialEq, Debug, Clone, Hash)]
249#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
250#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
251#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
252pub struct UpgradeInfo {
253 pub upgraded_id: ObjectId,
255 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
257 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
258 pub upgraded_version: Version,
259}
260
261#[derive(Eq, PartialEq, Debug, Clone, Hash)]
280#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
282#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
283pub struct MoveStruct {
284 #[cfg_attr(
286 feature = "serde",
287 serde(with = "::serde_with::As::<serialization::BinaryMoveStructType>")
288 )]
289 pub type_: StructTag,
290 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
294 pub version: Version,
295 #[cfg_attr(
297 feature = "serde",
298 serde(with = "::serde_with::As::<::serde_with::Bytes>")
299 )]
300 #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(32..=1024).lift()))]
301 pub contents: Vec<u8>,
302}
303
304#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
306pub enum ObjectType {
307 Package,
309 Struct(StructTag),
311}
312
313impl ObjectType {
314 crate::def_is!(Package);
315
316 crate::def_is_as_into_opt!(Struct(StructTag));
317}
318
319impl std::fmt::Display for ObjectType {
320 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 match self {
322 ObjectType::Package => write!(f, "Package"),
323 ObjectType::Struct(struct_tag) => write!(f, "Struct({struct_tag})"),
324 }
325 }
326}
327
328#[derive(Clone, Debug, PartialEq, Eq)]
338#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
339pub struct Object {
340 pub data: ObjectData,
342 pub owner: Owner,
344 pub previous_transaction: Digest,
346 pub storage_rebate: u64,
350}
351
352impl Object {
353 pub fn new(
355 data: ObjectData,
356 owner: Owner,
357 previous_transaction: Digest,
358 storage_rebate: u64,
359 ) -> Self {
360 Self {
361 data,
362 owner,
363 previous_transaction,
364 storage_rebate,
365 }
366 }
367
368 pub fn object_id(&self) -> ObjectId {
370 match &self.data {
371 ObjectData::Struct(struct_) => id_opt(&struct_.contents).unwrap(),
372 ObjectData::Package(package) => package.id,
373 }
374 }
375
376 #[cfg(all(feature = "hash", feature = "serde"))]
378 pub fn object_ref(&self) -> ObjectReference {
379 ObjectReference {
380 object_id: self.object_id(),
381 version: self.version(),
382 digest: self.digest(),
383 }
384 }
385
386 pub fn version(&self) -> Version {
388 match &self.data {
389 ObjectData::Struct(struct_) => struct_.version,
390 ObjectData::Package(package) => package.version,
391 }
392 }
393
394 pub fn object_type(&self) -> ObjectType {
396 match &self.data {
397 ObjectData::Struct(struct_) => ObjectType::Struct(struct_.type_.clone()),
398 ObjectData::Package(_) => ObjectType::Package,
399 }
400 }
401
402 pub fn as_struct_opt(&self) -> Option<&MoveStruct> {
404 match &self.data {
405 ObjectData::Struct(struct_) => Some(struct_),
406 _ => None,
407 }
408 }
409
410 pub fn as_struct(&self) -> &MoveStruct {
412 self.as_struct_opt().expect("not a move struct")
413 }
414
415 pub fn as_package_opt(&self) -> Option<&MovePackage> {
417 match &self.data {
418 ObjectData::Package(package) => Some(package),
419 _ => None,
420 }
421 }
422
423 pub fn as_package(&self) -> &MovePackage {
425 self.as_package_opt().expect("not a move package")
426 }
427
428 pub fn owner(&self) -> &Owner {
430 &self.owner
431 }
432
433 pub fn data(&self) -> &ObjectData {
435 &self.data
436 }
437
438 pub fn previous_transaction(&self) -> Digest {
440 self.previous_transaction
441 }
442
443 pub fn storage_rebate(&self) -> u64 {
448 self.storage_rebate
449 }
450
451 #[cfg(feature = "serde")]
452 pub fn to_rust<T: serde::de::DeserializeOwned>(&self) -> eyre::Result<T> {
453 use eyre::OptionExt;
454
455 Ok(bcs::from_bytes::<T>(
456 &self.as_struct_opt().ok_or_eyre("not a struct")?.contents,
457 )?)
458 }
459}
460
461fn id_opt(contents: &[u8]) -> Option<ObjectId> {
462 if ObjectId::LENGTH > contents.len() {
463 return None;
464 }
465
466 Some(ObjectId::from(
467 Address::from_bytes(&contents[..ObjectId::LENGTH]).unwrap(),
468 ))
469}
470
471#[derive(Clone, Debug, PartialEq, Eq)]
484#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
485pub struct GenesisObject {
486 pub data: ObjectData,
487 pub owner: Owner,
488}
489
490impl GenesisObject {
491 pub fn new(data: ObjectData, owner: Owner) -> Self {
492 Self { data, owner }
493 }
494
495 pub fn object_id(&self) -> ObjectId {
496 match &self.data {
497 ObjectData::Struct(struct_) => id_opt(&struct_.contents).unwrap(),
498 ObjectData::Package(package) => package.id,
499 }
500 }
501
502 pub fn version(&self) -> Version {
503 match &self.data {
504 ObjectData::Struct(struct_) => struct_.version,
505 ObjectData::Package(package) => package.version,
506 }
507 }
508
509 pub fn object_type(&self) -> ObjectType {
510 match &self.data {
511 ObjectData::Struct(struct_) => ObjectType::Struct(struct_.type_.clone()),
512 ObjectData::Package(_) => ObjectType::Package,
513 }
514 }
515
516 pub fn owner(&self) -> &Owner {
517 &self.owner
518 }
519
520 pub fn data(&self) -> &ObjectData {
521 &self.data
522 }
523}
524
525#[cfg(feature = "serde")]
527#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
528mod serialization {
529 use std::{borrow::Cow, str::FromStr};
530
531 use serde::{Deserialize, Deserializer, Serialize, Serializer};
532 use serde_with::{DeserializeAs, SerializeAs};
533
534 use super::*;
535 use crate::TypeTag;
536
537 #[derive(serde::Deserialize)]
544 enum MoveStructType {
545 Other(StructTag),
547 GasCoin,
549 StakedIota,
552 Coin(TypeTag),
555 }
559
560 #[derive(serde::Serialize)]
562 enum MoveStructTypeRef<'a> {
563 Other(&'a StructTag),
565 GasCoin,
567 StakedIota,
570 Coin(&'a TypeTag),
573 }
577
578 impl MoveStructType {
579 fn into_struct_tag(self) -> StructTag {
580 match self {
581 MoveStructType::Other(tag) => tag,
582 MoveStructType::GasCoin => StructTag::new_gas_coin(),
583 MoveStructType::StakedIota => StructTag::new_staked_iota(),
584 MoveStructType::Coin(type_tag) => StructTag::new_coin(type_tag),
585 }
586 }
587 }
588
589 impl<'a> MoveStructTypeRef<'a> {
590 fn from_struct_tag(s: &'a StructTag) -> Self {
591 let StructTag {
592 address,
593 module,
594 name,
595 type_params,
596 } = s;
597
598 if let Some(coin_type) = s.coin_type_opt() {
599 if let TypeTag::Struct(s_inner) = coin_type {
600 let StructTag {
601 address,
602 module,
603 name,
604 type_params,
605 } = s_inner.as_ref();
606
607 if address == &Address::FRAMEWORK
608 && module == "iota"
609 && name == "IOTA"
610 && type_params.is_empty()
611 {
612 return Self::GasCoin;
613 }
614 }
615
616 Self::Coin(coin_type)
617 } else if address == &Address::SYSTEM
618 && module == "staking_pool"
619 && name == "StakedIota"
620 && type_params.is_empty()
621 {
622 Self::StakedIota
623 } else {
624 Self::Other(s)
625 }
626 }
627 }
628
629 pub(super) struct BinaryMoveStructType;
630
631 impl SerializeAs<StructTag> for BinaryMoveStructType {
632 fn serialize_as<S>(source: &StructTag, serializer: S) -> Result<S::Ok, S::Error>
633 where
634 S: Serializer,
635 {
636 let move_object_type = MoveStructTypeRef::from_struct_tag(source);
637 move_object_type.serialize(serializer)
638 }
639 }
640
641 impl<'de> DeserializeAs<'de, StructTag> for BinaryMoveStructType {
642 fn deserialize_as<D>(deserializer: D) -> Result<StructTag, D::Error>
643 where
644 D: Deserializer<'de>,
645 {
646 let struct_type = MoveStructType::deserialize(deserializer)?;
647 Ok(struct_type.into_struct_tag())
648 }
649 }
650
651 struct ReadableObjectType;
652
653 impl SerializeAs<ObjectType> for ReadableObjectType {
654 fn serialize_as<S>(source: &ObjectType, serializer: S) -> Result<S::Ok, S::Error>
655 where
656 S: Serializer,
657 {
658 match source {
659 ObjectType::Package => "package".serialize(serializer),
660 ObjectType::Struct(s) => s.serialize(serializer),
661 }
662 }
663 }
664
665 impl<'de> DeserializeAs<'de, ObjectType> for ReadableObjectType {
666 fn deserialize_as<D>(deserializer: D) -> Result<ObjectType, D::Error>
667 where
668 D: Deserializer<'de>,
669 {
670 let s: Cow<'de, str> = Deserialize::deserialize(deserializer)?;
671 if s == "package" {
672 Ok(ObjectType::Package)
673 } else {
674 let struct_tag = StructTag::from_str(&s)
675 .map_err(|_| serde::de::Error::custom("invalid object type"))?;
676 Ok(ObjectType::Struct(struct_tag))
677 }
678 }
679 }
680
681 #[derive(serde::Serialize, serde::Deserialize)]
682 #[serde(rename = "Object")]
683 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
684 struct ReadableObject {
685 object_id: ObjectId,
686 #[serde(with = "crate::_serde::ReadableDisplay")]
687 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
688 version: Version,
689 owner: Owner,
690 #[serde(with = "::serde_with::As::<ReadableObjectType>")]
691 #[serde(rename = "type")]
692 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
693 type_: ObjectType,
694 #[serde(flatten)]
695 data: ReadableObjectData,
696 previous_transaction: Digest,
697 #[serde(with = "crate::_serde::ReadableDisplay")]
698 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
699 storage_rebate: u64,
700 }
701
702 #[cfg(feature = "schemars")]
703 impl schemars::JsonSchema for Object {
704 fn schema_name() -> String {
705 ReadableObject::schema_name()
706 }
707
708 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
709 ReadableObject::json_schema(gen)
710 }
711 }
712
713 #[derive(serde::Serialize, serde::Deserialize)]
714 #[serde(untagged)]
715 #[cfg_attr(
716 feature = "schemars",
717 derive(schemars::JsonSchema),
718 schemars(rename = "ObjectData")
719 )]
720 enum ReadableObjectData {
721 Move(ReadableMoveStruct),
722 Package(ReadablePackage),
723 }
724
725 #[derive(serde::Serialize, serde::Deserialize)]
726 #[cfg_attr(
727 feature = "schemars",
728 derive(schemars::JsonSchema),
729 schemars(rename = "Package")
730 )]
731 struct ReadablePackage {
732 #[serde(
733 with = "::serde_with::As::<BTreeMap<::serde_with::Same, crate::_serde::Base64Encoded>>"
734 )]
735 #[cfg_attr(
736 feature = "schemars",
737 schemars(with = "BTreeMap<Identifier, crate::_schemars::Base64>")
738 )]
739 modules: BTreeMap<Identifier, Vec<u8>>,
740 type_origin_table: Vec<TypeOrigin>,
741 linkage_table: BTreeMap<ObjectId, UpgradeInfo>,
742 }
743
744 #[derive(serde::Serialize, serde::Deserialize)]
745 #[cfg_attr(
746 feature = "schemars",
747 derive(schemars::JsonSchema),
748 schemars(rename = "MoveStruct")
749 )]
750 struct ReadableMoveStruct {
751 #[serde(with = "::serde_with::As::<crate::_serde::Base64Encoded>")]
752 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::Base64"))]
753 contents: Vec<u8>,
754 }
755
756 impl Object {
757 fn readable_object_data(&self) -> ReadableObjectData {
758 match &self.data {
759 ObjectData::Struct(struct_) => ReadableObjectData::Move(ReadableMoveStruct {
760 contents: struct_.contents.clone(),
761 }),
762 ObjectData::Package(package) => ReadableObjectData::Package(ReadablePackage {
763 modules: package.modules.clone(),
764 type_origin_table: package.type_origin_table.clone(),
765 linkage_table: package.linkage_table.clone(),
766 }),
767 }
768 }
769 }
770
771 impl Serialize for Object {
772 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
773 where
774 S: Serializer,
775 {
776 if serializer.is_human_readable() {
777 let readable = ReadableObject {
778 object_id: self.object_id(),
779 version: self.version(),
780 owner: self.owner,
782 previous_transaction: self.previous_transaction,
783 storage_rebate: self.storage_rebate,
784 type_: self.object_type(),
785 data: self.readable_object_data(),
786 };
787 readable.serialize(serializer)
788 } else {
789 let binary = BinaryObject {
790 data: self.data.clone(),
791 owner: self.owner,
792 previous_transaction: self.previous_transaction,
793 storage_rebate: self.storage_rebate,
794 };
795 binary.serialize(serializer)
796 }
797 }
798 }
799
800 impl<'de> Deserialize<'de> for Object {
801 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
802 where
803 D: Deserializer<'de>,
804 {
805 if deserializer.is_human_readable() {
806 let ReadableObject {
807 object_id,
808 version,
809 owner,
810 previous_transaction,
811 storage_rebate,
812 type_,
813 data,
814 } = Deserialize::deserialize(deserializer)?;
815
816 let data = match (type_, data) {
818 (
819 ObjectType::Package,
820 ReadableObjectData::Package(ReadablePackage {
821 modules,
822 type_origin_table,
823 linkage_table,
824 }),
825 ) => ObjectData::Package(MovePackage {
826 id: object_id,
827 version,
828 modules,
829 type_origin_table,
830 linkage_table,
831 }),
832 (
833 ObjectType::Struct(type_),
834 ReadableObjectData::Move(ReadableMoveStruct { contents }),
835 ) => {
836 if id_opt(&contents).is_none_or(|id| id != object_id) {
838 return Err(serde::de::Error::custom("id from contents doesn't match"));
839 }
840
841 ObjectData::Struct(MoveStruct {
842 type_,
843 version,
844 contents,
845 })
846 }
847 _ => return Err(serde::de::Error::custom("type and data don't match")),
848 };
849
850 Ok(Object {
851 data,
852 owner,
853 previous_transaction,
854 storage_rebate,
855 })
856 } else {
857 let BinaryObject {
858 data,
859 owner,
860 previous_transaction,
861 storage_rebate,
862 } = Deserialize::deserialize(deserializer)?;
863
864 Ok(Object {
865 data,
866 owner,
867 previous_transaction,
868 storage_rebate,
869 })
870 }
871 }
872 }
873
874 #[derive(serde::Serialize, serde::Deserialize)]
875 struct BinaryObject {
876 data: ObjectData,
877 owner: Owner,
878 previous_transaction: Digest,
879 storage_rebate: u64,
880 }
881
882 #[derive(serde::Serialize, serde::Deserialize)]
883 #[serde(rename = "GenesisObject")]
884 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
885 struct ReadableGenesisObject {
886 object_id: ObjectId,
887 #[serde(with = "crate::_serde::ReadableDisplay")]
888 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
889 version: Version,
890 owner: Owner,
891 #[serde(with = "::serde_with::As::<ReadableObjectType>")]
892 #[serde(rename = "type")]
893 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
894 type_: ObjectType,
895 #[serde(flatten)]
896 data: ReadableObjectData,
897 }
898
899 #[cfg(feature = "schemars")]
900 impl schemars::JsonSchema for GenesisObject {
901 fn schema_name() -> String {
902 ReadableGenesisObject::schema_name()
903 }
904
905 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
906 ReadableGenesisObject::json_schema(gen)
907 }
908 }
909
910 #[derive(serde::Serialize, serde::Deserialize)]
911 enum BinaryGenesisObject {
912 RawObject { data: ObjectData, owner: Owner },
913 }
914
915 impl GenesisObject {
916 fn readable_object_data(&self) -> ReadableObjectData {
917 match &self.data {
918 ObjectData::Struct(struct_) => ReadableObjectData::Move(ReadableMoveStruct {
919 contents: struct_.contents.clone(),
920 }),
921 ObjectData::Package(package) => ReadableObjectData::Package(ReadablePackage {
922 modules: package.modules.clone(),
923 type_origin_table: package.type_origin_table.clone(),
924 linkage_table: package.linkage_table.clone(),
925 }),
926 }
927 }
928 }
929
930 impl Serialize for GenesisObject {
931 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
932 where
933 S: Serializer,
934 {
935 if serializer.is_human_readable() {
936 let readable = ReadableGenesisObject {
937 object_id: self.object_id(),
938 version: self.version(),
939 owner: self.owner,
940 type_: self.object_type(),
941 data: self.readable_object_data(),
942 };
943 readable.serialize(serializer)
944 } else {
945 let binary = BinaryGenesisObject::RawObject {
946 data: self.data.clone(),
947 owner: self.owner,
948 };
949 binary.serialize(serializer)
950 }
951 }
952 }
953
954 impl<'de> Deserialize<'de> for GenesisObject {
955 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
956 where
957 D: Deserializer<'de>,
958 {
959 if deserializer.is_human_readable() {
960 let ReadableGenesisObject {
961 object_id,
962 version,
963 owner,
964 type_,
965 data,
966 } = Deserialize::deserialize(deserializer)?;
967
968 let data = match (type_, data) {
970 (
971 ObjectType::Package,
972 ReadableObjectData::Package(ReadablePackage {
973 modules,
974 type_origin_table,
975 linkage_table,
976 }),
977 ) => ObjectData::Package(MovePackage {
978 id: object_id,
979 version,
980 modules,
981 type_origin_table,
982 linkage_table,
983 }),
984 (
985 ObjectType::Struct(type_),
986 ReadableObjectData::Move(ReadableMoveStruct { contents }),
987 ) => {
988 if id_opt(&contents).is_none_or(|id| id != object_id) {
990 return Err(serde::de::Error::custom("id from contents doesn't match"));
991 }
992
993 ObjectData::Struct(MoveStruct {
994 type_,
995 version,
996 contents,
997 })
998 }
999 _ => return Err(serde::de::Error::custom("type and data don't match")),
1000 };
1001
1002 Ok(GenesisObject { data, owner })
1003 } else {
1004 let BinaryGenesisObject::RawObject { data, owner } =
1005 Deserialize::deserialize(deserializer)?;
1006
1007 Ok(GenesisObject { data, owner })
1008 }
1009 }
1010 }
1011
1012 #[cfg(test)]
1013 mod tests {
1014 #[cfg(target_arch = "wasm32")]
1015 use wasm_bindgen_test::wasm_bindgen_test as test;
1016
1017 use super::*;
1018 use crate::object::Object;
1019
1020 #[test]
1021 fn obj() {
1022 let o = Object {
1023 data: ObjectData::Struct(MoveStruct {
1024 type_: StructTag {
1025 address: Address::FRAMEWORK,
1026 module: Identifier::new("bar").unwrap(),
1027 name: Identifier::new("foo").unwrap(),
1028 type_params: Vec::new(),
1029 },
1030 version: 12,
1031 contents: ObjectId::ZERO.into(),
1032 }),
1033 owner: Owner::Object(ObjectId::ZERO),
1035 previous_transaction: Digest::ZERO,
1040 storage_rebate: 100,
1041 };
1042
1043 println!("{}", serde_json::to_string_pretty(&o).unwrap());
1044 println!(
1045 "{}",
1046 serde_json::to_string_pretty(&ObjectReference {
1047 object_id: ObjectId::ZERO,
1048 version: 1,
1049 digest: Digest::ZERO,
1050 })
1051 .unwrap()
1052 );
1053 }
1054
1055 #[test]
1056 fn object_fixture() {
1057 const IOTA_COIN: &[u8] = &[
1058 0, 1, 32, 79, 43, 0, 0, 0, 0, 0, 40, 35, 95, 175, 213, 151, 87, 206, 190, 35, 131,
1059 79, 35, 254, 22, 15, 181, 40, 108, 28, 77, 68, 229, 107, 254, 191, 160, 196, 186,
1060 42, 2, 122, 53, 52, 133, 199, 58, 0, 0, 0, 0, 0, 79, 255, 208, 0, 85, 34, 190, 75,
1061 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155, 144, 230, 47, 97,
1062 220, 21, 24, 30, 26, 62, 32, 17, 197, 192, 38, 64, 173, 142, 143, 49, 111, 15, 211,
1063 92, 84, 48, 160, 243, 102, 229, 253, 251, 137, 210, 101, 119, 173, 228, 51, 141,
1064 20, 15, 85, 96, 19, 15, 0, 0, 0, 0, 0,
1065 ];
1066
1067 const IOTA_STAKE: &[u8] = &[
1068 0, 2, 154, 1, 52, 5, 0, 0, 0, 0, 80, 3, 112, 71, 231, 166, 234, 205, 164, 99, 237,
1069 29, 56, 97, 170, 21, 96, 105, 158, 227, 122, 22, 251, 60, 162, 12, 97, 151, 218,
1070 71, 253, 231, 239, 116, 138, 12, 233, 128, 195, 128, 77, 33, 38, 122, 77, 53, 154,
1071 197, 198, 75, 212, 12, 182, 163, 224, 42, 82, 123, 69, 248, 40, 207, 143, 211, 13,
1072 106, 1, 0, 0, 0, 0, 0, 0, 59, 81, 183, 246, 112, 0, 0, 0, 0, 79, 255, 208, 0, 85,
1073 34, 190, 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155, 144,
1074 230, 47, 97, 220, 21, 24, 30, 26, 62, 32, 247, 239, 248, 71, 247, 102, 190, 149,
1075 232, 153, 138, 67, 169, 209, 203, 29, 255, 215, 223, 57, 159, 44, 40, 218, 166, 13,
1076 80, 71, 14, 188, 232, 68, 0, 0, 0, 0, 0, 0, 0, 0,
1077 ];
1078
1079 const NFT: &[u8] = &[
1080 0, 0, 97, 201, 195, 159, 216, 97, 133, 173, 96, 215, 56, 212, 229, 43, 208, 139,
1081 218, 7, 29, 54, 106, 205, 224, 126, 7, 195, 145, 106, 45, 117, 168, 22, 12, 100,
1082 105, 115, 116, 114, 105, 98, 117, 116, 105, 111, 110, 11, 68, 69, 69, 80, 87, 114,
1083 97, 112, 112, 101, 114, 0, 124, 24, 223, 4, 0, 0, 0, 0, 40, 31, 8, 18, 84, 38, 164,
1084 252, 84, 115, 250, 246, 137, 132, 128, 186, 156, 36, 62, 18, 140, 21, 4, 90, 209,
1085 105, 85, 84, 92, 214, 97, 81, 207, 64, 194, 198, 208, 21, 0, 0, 0, 0, 79, 255, 208,
1086 0, 85, 34, 190, 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155,
1087 144, 230, 47, 97, 220, 21, 24, 30, 26, 62, 32, 170, 4, 94, 114, 207, 155, 31, 80,
1088 62, 254, 220, 206, 240, 218, 83, 54, 204, 197, 255, 239, 41, 66, 199, 150, 56, 189,
1089 86, 217, 166, 216, 128, 241, 64, 205, 21, 0, 0, 0, 0, 0,
1090 ];
1091
1092 const FUD_COIN: &[u8] = &[
1093 0, 3, 7, 118, 203, 129, 155, 1, 171, 237, 80, 43, 238, 138, 112, 43, 76, 45, 84,
1094 117, 50, 193, 47, 37, 0, 28, 157, 234, 121, 90, 94, 99, 28, 38, 241, 3, 102, 117,
1095 100, 3, 70, 85, 68, 0, 193, 89, 252, 3, 0, 0, 0, 0, 40, 33, 214, 90, 11, 56, 243,
1096 115, 10, 250, 121, 250, 28, 34, 237, 104, 130, 148, 40, 130, 29, 248, 137, 244, 27,
1097 138, 94, 150, 28, 182, 104, 162, 185, 0, 152, 247, 62, 93, 1, 0, 0, 0, 42, 95, 32,
1098 226, 13, 31, 128, 91, 188, 127, 235, 12, 75, 73, 116, 112, 3, 227, 244, 126, 59,
1099 81, 214, 118, 144, 243, 195, 17, 82, 216, 119, 170, 32, 239, 247, 71, 249, 241, 98,
1100 133, 53, 46, 37, 100, 242, 94, 231, 241, 184, 8, 69, 192, 69, 67, 1, 116, 251, 229,
1101 226, 99, 119, 79, 255, 71, 43, 64, 242, 19, 0, 0, 0, 0, 0,
1102 ];
1103
1104 const BULLSHARK_PACKAGE: &[u8] = &[
1105 1, 135, 35, 29, 28, 138, 126, 114, 145, 204, 122, 145, 8, 244, 199, 188, 26, 10,
1106 28, 14, 182, 55, 91, 91, 97, 10, 245, 202, 35, 223, 14, 140, 86, 1, 0, 0, 0, 0, 0,
1107 0, 0, 1, 9, 98, 117, 108, 108, 115, 104, 97, 114, 107, 162, 6, 161, 28, 235, 11, 6,
1108 0, 0, 0, 10, 1, 0, 12, 2, 12, 36, 3, 48, 61, 4, 109, 12, 5, 121, 137, 1, 7, 130, 2,
1109 239, 1, 8, 241, 3, 96, 6, 209, 4, 82, 10, 163, 5, 5, 12, 168, 5, 75, 0, 7, 1, 16,
1110 2, 9, 2, 21, 2, 22, 2, 23, 0, 0, 2, 0, 1, 3, 7, 1, 0, 0, 2, 1, 12, 1, 0, 1, 2, 2,
1111 12, 1, 0, 1, 2, 4, 12, 1, 0, 1, 4, 5, 2, 0, 5, 6, 7, 0, 0, 12, 0, 1, 0, 0, 13, 2,
1112 1, 0, 0, 8, 3, 1, 0, 1, 20, 7, 8, 1, 0, 2, 8, 18, 19, 1, 0, 2, 10, 10, 11, 1, 2, 2,
1113 14, 17, 1, 1, 0, 3, 17, 7, 1, 1, 12, 3, 18, 16, 1, 1, 12, 4, 19, 13, 14, 0, 5, 15,
1114 5, 6, 0, 3, 6, 5, 9, 7, 12, 8, 15, 6, 9, 4, 9, 2, 8, 0, 7, 8, 5, 0, 4, 7, 11, 4, 1,
1115 8, 0, 3, 5, 7, 8, 5, 2, 7, 11, 4, 1, 8, 0, 11, 2, 1, 8, 0, 2, 11, 3, 1, 8, 0, 11,
1116 4, 1, 8, 0, 1, 10, 2, 1, 8, 6, 1, 9, 0, 1, 11, 1, 1, 9, 0, 1, 8, 0, 7, 9, 0, 2, 10,
1117 2, 10, 2, 10, 2, 11, 1, 1, 8, 6, 7, 8, 5, 2, 11, 4, 1, 9, 0, 11, 3, 1, 9, 0, 1, 11,
1118 3, 1, 8, 0, 1, 6, 8, 5, 1, 5, 1, 11, 4, 1, 8, 0, 2, 9, 0, 5, 4, 7, 11, 4, 1, 9, 0,
1119 3, 5, 7, 8, 5, 2, 7, 11, 4, 1, 9, 0, 11, 2, 1, 9, 0, 1, 3, 9, 66, 85, 76, 76, 83,
1120 72, 65, 82, 75, 4, 67, 111, 105, 110, 12, 67, 111, 105, 110, 77, 101, 116, 97, 100,
1121 97, 116, 97, 6, 79, 112, 116, 105, 111, 110, 11, 84, 114, 101, 97, 115, 117, 114,
1122 121, 67, 97, 112, 9, 84, 120, 67, 111, 110, 116, 101, 120, 116, 3, 85, 114, 108, 9,
1123 98, 117, 108, 108, 115, 104, 97, 114, 107, 4, 98, 117, 114, 110, 4, 99, 111, 105,
1124 110, 15, 99, 114, 101, 97, 116, 101, 95, 99, 117, 114, 114, 101, 110, 99, 121, 11,
1125 100, 117, 109, 109, 121, 95, 102, 105, 101, 108, 100, 4, 105, 110, 105, 116, 4,
1126 109, 105, 110, 116, 17, 109, 105, 110, 116, 95, 97, 110, 100, 95, 116, 114, 97,
1127 110, 115, 102, 101, 114, 21, 110, 101, 119, 95, 117, 110, 115, 97, 102, 101, 95,
1128 102, 114, 111, 109, 95, 98, 121, 116, 101, 115, 6, 111, 112, 116, 105, 111, 110,
1129 20, 112, 117, 98, 108, 105, 99, 95, 102, 114, 101, 101, 122, 101, 95, 111, 98, 106,
1130 101, 99, 116, 15, 112, 117, 98, 108, 105, 99, 95, 116, 114, 97, 110, 115, 102, 101,
1131 114, 6, 115, 101, 110, 100, 101, 114, 4, 115, 111, 109, 101, 8, 116, 114, 97, 110,
1132 115, 102, 101, 114, 10, 116, 120, 95, 99, 111, 110, 116, 101, 120, 116, 3, 117,
1133 114, 108, 135, 35, 29, 28, 138, 126, 114, 145, 204, 122, 145, 8, 244, 199, 188, 26,
1134 10, 28, 14, 182, 55, 91, 91, 97, 10, 245, 202, 35, 223, 14, 140, 86, 0, 0, 0, 0, 0,
1135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1137 0, 0, 2, 10, 2, 10, 9, 66, 85, 76, 76, 83, 72, 65, 82, 75, 10, 2, 20, 19, 66, 117,
1138 108, 108, 32, 83, 104, 97, 114, 107, 32, 83, 117, 105, 70, 114, 101, 110, 115, 10,
1139 2, 1, 0, 10, 2, 39, 38, 104, 116, 116, 112, 115, 58, 47, 47, 105, 46, 105, 98, 98,
1140 46, 99, 111, 47, 104, 87, 89, 50, 87, 53, 120, 47, 98, 117, 108, 108, 115, 104, 97,
1141 114, 107, 46, 112, 110, 103, 0, 2, 1, 11, 1, 0, 0, 0, 0, 4, 20, 11, 0, 49, 6, 7, 0,
1142 7, 1, 7, 2, 7, 3, 17, 10, 56, 0, 10, 1, 56, 1, 12, 2, 12, 3, 11, 2, 56, 2, 11, 3,
1143 11, 1, 46, 17, 9, 56, 3, 2, 1, 1, 4, 0, 1, 6, 11, 0, 11, 1, 11, 2, 11, 3, 56, 4, 2,
1144 2, 1, 4, 0, 1, 5, 11, 0, 11, 1, 56, 5, 1, 2, 0, 1, 9, 98, 117, 108, 108, 115, 104,
1145 97, 114, 107, 9, 66, 85, 76, 76, 83, 72, 65, 82, 75, 135, 35, 29, 28, 138, 126,
1146 114, 145, 204, 122, 145, 8, 244, 199, 188, 26, 10, 28, 14, 182, 55, 91, 91, 97, 10,
1147 245, 202, 35, 223, 14, 140, 86, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
1150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1151 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1152 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 3, 32, 87, 145, 191, 231, 147, 185,
1153 46, 159, 240, 181, 95, 126, 236, 65, 154, 55, 16, 196, 229, 218, 47, 59, 99, 197,
1154 13, 89, 18, 159, 205, 129, 112, 131, 112, 192, 126, 0, 0, 0, 0, 0,
1155 ];
1156
1157 for fixture in [IOTA_COIN, IOTA_STAKE, NFT, FUD_COIN, BULLSHARK_PACKAGE] {
1158 let object: Object = bcs::from_bytes(fixture).unwrap();
1159 assert_eq!(bcs::to_bytes(&object).unwrap(), fixture);
1160
1161 let json = serde_json::to_string_pretty(&object).unwrap();
1162 println!("{json}");
1163 assert_eq!(object, serde_json::from_str(&json).unwrap());
1164 }
1165 }
1166 }
1167}