dpp/identity/conversion/platform_value/
mod.rs1use crate::identity::{Identity, IdentityV0};
2use crate::version::PlatformVersion;
3use crate::ProtocolError;
4use platform_value::Value;
5use platform_version::TryFromPlatformVersioned;
6
7impl TryFromPlatformVersioned<Value> for Identity {
8 type Error = ProtocolError;
9
10 fn try_from_platform_versioned(
11 value: Value,
12 platform_version: &PlatformVersion,
13 ) -> Result<Self, Self::Error> {
14 match platform_version
15 .dpp
16 .identity_versions
17 .identity_structure_version
18 {
19 0 => {
20 let identity_v0: IdentityV0 =
21 platform_value::from_value(value).map_err(ProtocolError::ValueError)?;
22 Ok(identity_v0.into())
23 }
24 version => Err(ProtocolError::UnknownVersionMismatch {
25 method: "Identity::try_from_owned_value".to_string(),
26 known_versions: vec![0],
27 received: version,
28 }),
29 }
30 }
31}
32
33impl TryFromPlatformVersioned<&Value> for Identity {
34 type Error = ProtocolError;
35
36 fn try_from_platform_versioned(
37 value: &Value,
38 platform_version: &PlatformVersion,
39 ) -> Result<Self, Self::Error> {
40 match platform_version
41 .dpp
42 .identity_versions
43 .identity_structure_version
44 {
45 0 => {
46 let identity_v0: IdentityV0 =
47 platform_value::from_value(value.clone()).map_err(ProtocolError::ValueError)?;
48 Ok(identity_v0.into())
49 }
50 version => Err(ProtocolError::UnknownVersionMismatch {
51 method: "Identity::try_from_owned_value".to_string(),
52 known_versions: vec![0],
53 received: version,
54 }),
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use crate::identity::accessors::IdentityGettersV0;
63 use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
64 use crate::identity::IdentityPublicKey;
65 use crate::identity::{KeyType, Purpose, SecurityLevel};
66 use crate::serialization::ValueConvertible;
67 use platform_value::{platform_value, BinaryData, Identifier};
68 use platform_version::version::LATEST_PLATFORM_VERSION;
69 use std::collections::BTreeMap;
70
71 fn sample_identity_v0() -> IdentityV0 {
72 let mut keys: BTreeMap<u32, IdentityPublicKey> = BTreeMap::new();
73 keys.insert(
74 0,
75 IdentityPublicKey::V0(IdentityPublicKeyV0 {
76 id: 0,
77 purpose: Purpose::AUTHENTICATION,
78 security_level: SecurityLevel::MASTER,
79 contract_bounds: None,
80 key_type: KeyType::ECDSA_SECP256K1,
81 read_only: false,
82 data: BinaryData::new(vec![0x01; 33]),
83 disabled_at: None,
84 }),
85 );
86 IdentityV0 {
87 id: Identifier::from([42u8; 32]),
88 public_keys: keys,
89 balance: 7,
90 revision: 2,
91 }
92 }
93
94 fn tagged_raw_value() -> Value {
110 use platform_value::string_encoding::{encode, Encoding};
111 let data_b64 = encode(&[0x22u8; 33], Encoding::Base64);
112 platform_value!({
113 "id": Identifier::from([7u8; 32]),
114 "publicKeys": [
115 {
116 "$formatVersion": "0",
117 "id": 0u32,
118 "type": 0u8,
119 "purpose": 0u8,
120 "securityLevel": 0u8,
121 "contractBounds": Value::Null,
122 "data": data_b64,
123 "readOnly": false,
124 "disabledAt": Value::Null,
125 }
126 ],
127 "balance": 100u64,
128 "revision": 1u64,
129 })
130 }
131
132 #[test]
133 fn try_from_platform_versioned_owned_value_parses_legacy_shape() {
134 let value = tagged_raw_value();
135 let identity = Identity::try_from_platform_versioned(value, LATEST_PLATFORM_VERSION)
136 .expect("should parse legacy raw object");
137 assert_eq!(identity.balance(), 100);
138 assert_eq!(identity.revision(), 1);
139 assert_eq!(identity.public_keys().len(), 1);
140 }
141
142 #[test]
143 fn try_from_platform_versioned_ref_value_parses_legacy_shape() {
144 let value = tagged_raw_value();
145 let identity = Identity::try_from_platform_versioned(&value, LATEST_PLATFORM_VERSION)
146 .expect("should parse legacy raw object from &Value");
147 assert_eq!(identity.balance(), 100);
148 }
149
150 #[test]
151 fn try_from_platform_versioned_errors_on_garbage_owned() {
152 let value = Value::Null;
153 let result = Identity::try_from_platform_versioned(value, LATEST_PLATFORM_VERSION);
154 assert!(matches!(result, Err(ProtocolError::ValueError(_))));
155 }
156
157 #[test]
158 fn try_from_platform_versioned_errors_on_garbage_ref() {
159 let value = Value::Text("not a map".to_string());
160 let result = Identity::try_from_platform_versioned(&value, LATEST_PLATFORM_VERSION);
161 assert!(matches!(result, Err(ProtocolError::ValueError(_))));
162 }
163
164 #[test]
168 fn identity_wrapper_to_object_includes_format_version_tag() {
169 let identity: Identity = sample_identity_v0().into();
170 let value = identity.to_object().expect("to_object");
171 let map = value.to_map_ref().expect("map");
172 assert!(
173 map.iter()
174 .any(|(k, _)| k.as_text() == Some("$formatVersion")),
175 "Identity enum wrapper must keep its format version tag"
176 );
177 }
178
179 #[test]
180 fn identity_wrapper_to_object_differs_from_v0_inner_shape() {
181 let v0 = sample_identity_v0();
184 let wrapper: Identity = v0.clone().into();
185 let inner_value = v0.to_object().unwrap();
186 let outer_value = wrapper.to_object().unwrap();
187 assert_ne!(inner_value, outer_value);
188 }
189}