iota_sdk_types/
move_package.rs1use crate::{Digest, ObjectId};
5
6#[repr(u8)]
8#[derive(strum::Display, Debug, Clone, Copy, PartialEq, Eq)]
9#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
10pub enum UpgradePolicy {
11 Compatible = 0,
17 Additive = 128,
20 DepOnly = 192,
22}
23
24impl UpgradePolicy {
25 pub const COMPATIBLE: u8 = Self::Compatible as u8;
26 pub const ADDITIVE: u8 = Self::Additive as u8;
27 pub const DEP_ONLY: u8 = Self::DepOnly as u8;
28
29 pub fn is_valid_policy(policy: &u8) -> bool {
30 Self::try_from(*policy).is_ok()
31 }
32}
33
34impl TryFrom<u8> for UpgradePolicy {
35 type Error = ();
36 fn try_from(value: u8) -> Result<Self, Self::Error> {
37 match value {
38 x if x == Self::Compatible as u8 => Ok(Self::Compatible),
39 x if x == Self::Additive as u8 => Ok(Self::Additive),
40 x if x == Self::DepOnly as u8 => Ok(Self::DepOnly),
41 _ => Err(()),
42 }
43 }
44}
45
46#[derive(Clone, Debug)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub struct MovePackageData {
51 #[cfg_attr(feature = "serde", serde(with = "serialization::modules"))]
53 pub modules: Vec<Vec<u8>>,
54 pub dependencies: Vec<ObjectId>,
56 #[cfg_attr(feature = "serde", serde(with = "serialization::digest"))]
58 pub digest: Digest,
59}
60
61impl MovePackageData {
62 #[cfg(feature = "hash")]
63 pub fn new(modules: Vec<Vec<u8>>, dependencies: Vec<ObjectId>) -> Self {
64 use crate::hash::Hasher;
65 let mut components = dependencies
66 .iter()
67 .map(|o| o.into_inner())
68 .chain(modules.iter().map(|module| {
69 let mut hasher = Hasher::new();
70 hasher.update(module);
71 hasher.finalize().into_inner()
72 }))
73 .collect::<Vec<_>>();
74
75 components.sort();
78
79 let mut hasher = Hasher::new();
80 for c in components {
81 hasher.update(c);
82 }
83
84 Self {
85 modules,
86 dependencies,
87 digest: Digest::from(hasher.finalize().into_inner()),
88 }
89 }
90}
91
92#[cfg(feature = "serde")]
93mod serialization {
94 use base64ct::Encoding;
95 use serde::{Deserialize, Deserializer, Serialize, Serializer};
96
97 use super::*;
98
99 impl MovePackageData {
100 pub fn to_base64(&self) -> String {
101 base64ct::Base64::encode_string(&bcs::to_bytes(self).expect("bcs encoding failed"))
102 }
103
104 pub fn from_base64(base64: &str) -> Result<Self, bcs::Error> {
105 use serde::de::Error;
106 bcs::from_bytes(&base64ct::Base64::decode_vec(base64).map_err(bcs::Error::custom)?)
107 }
108 }
109
110 pub mod modules {
111 use super::*;
112
113 pub fn serialize<S: Serializer>(
114 value: &[Vec<u8>],
115 serializer: S,
116 ) -> Result<S::Ok, S::Error> {
117 value
118 .iter()
119 .map(|v| base64ct::Base64::encode_string(v))
120 .collect::<Vec<_>>()
121 .serialize(serializer)
122 }
123
124 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
125 where
126 D: Deserializer<'de>,
127 {
128 let bcs = Vec::<String>::deserialize(deserializer)?;
129 bcs.into_iter()
130 .map(|s| base64ct::Base64::decode_vec(&s).map_err(serde::de::Error::custom))
131 .collect()
132 }
133 }
134
135 pub mod digest {
136 use super::*;
137
138 pub fn serialize<S: Serializer>(value: &Digest, serializer: S) -> Result<S::Ok, S::Error> {
139 value.as_bytes().serialize(serializer)
140 }
141
142 pub fn deserialize<'de, D>(deserializer: D) -> Result<Digest, D::Error>
143 where
144 D: Deserializer<'de>,
145 {
146 let bytes = Vec::<u8>::deserialize(deserializer)?;
147 Digest::from_bytes(bytes).map_err(|e| serde::de::Error::custom(format!("{e}")))
148 }
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 const PACKAGE: &str = r#"{"modules":["oRzrCwYAAAAKAQAIAggUAxw+BFoGBWBBB6EBwQEI4gJACqIDGgy8A5cBDdMEBgAKAQ0BEwEUAAIMAAABCAAAAAgAAQQEAAMDAgAACAABAAAJAgMAABACAwAAEgQDAAAMBQYAAAYHAQAAEQgBAAAFCQoAAQsACwACDg8BAQwCEw8BAQgDDwwNAAoOCgYJBgEHCAQAAQYIAAEDAQYIAQQHCAEDAwcIBAEIAAQDAwUHCAQDCAAFBwgEAgMHCAQBCAIBCAMBBggEAQUBCAECCQAFBkNvbmZpZwVGb3JnZQVTd29yZAlUeENvbnRleHQDVUlEDWNyZWF0ZV9jb25maWcMY3JlYXRlX3N3b3JkAmlkBGluaXQFbWFnaWMJbXlfbW9kdWxlA25ldwluZXdfc3dvcmQGb2JqZWN0D3B1YmxpY190cmFuc2ZlcgZzZW5kZXIIc3RyZW5ndGgOc3dvcmRfdHJhbnNmZXIOc3dvcmRzX2NyZWF0ZWQIdHJhbnNmZXIKdHhfY29udGV4dAV2YWx1ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgMHCAMJAxADAQICBwgDEgMCAgIHCAMVAwAAAAABCQoAEQgGAAAAAAAAAAASAQsALhELOAACAQEAAAEECwAQABQCAgEAAAEECwAQARQCAwEAAAEECwAQAhQCBAEAAAEOCgAQAhQGAQAAAAAAAAAWCwAPAhULAxEICwELAhIAAgUBAAABCAsDEQgLAAsBEgALAjgBAgYBAAABBAsACwE4AgIHAQAAAQULAREICwASAgIAAQACAQEA"],"dependencies":["0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000001"],"digest":[246,127,102,77,186,19,68,12,161,181,56,248,210,0,91,211,245,251,165,152,0,197,250,135,171,37,177,240,133,76,122,124]}"#;
157
158 #[test]
159 fn test_serialization() {
160 let package: MovePackageData = serde_json::from_str(PACKAGE).unwrap();
161 let new_json = serde_json::to_string(&package).unwrap();
162 assert_eq!(new_json, PACKAGE);
163 }
164
165 #[test]
166 fn test_digest() {
167 let json_package: MovePackageData = serde_json::from_str(PACKAGE).unwrap();
168 let package = MovePackageData::new(json_package.modules, json_package.dependencies);
169 assert_eq!(json_package.digest, package.digest);
170 }
171}