dpp/identity/v0/conversion/
platform_value.rs1use crate::identity::conversion::platform_value::IdentityPlatformValueConversionMethodsV0;
2use crate::identity::{property_names, IdentityV0};
3#[cfg(feature = "value-conversion")]
4use crate::serialization::ValueConvertible;
5use crate::ProtocolError;
6use platform_value::Value;
7
8impl IdentityPlatformValueConversionMethodsV0 for IdentityV0 {
9 fn to_cleaned_object(&self) -> Result<Value, ProtocolError> {
10 let mut value = self.to_object()?;
12 if let Some(keys) = value.get_optional_array_mut_ref(property_names::PUBLIC_KEYS)? {
13 for key in keys.iter_mut() {
14 key.remove_optional_value_if_null("disabledAt")?;
15 }
16 }
17 Ok(value)
18 }
19}
20
21#[cfg(test)]
22mod tests {
23 use super::*;
24 use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
25 use crate::identity::{IdentityPublicKey, KeyType, Purpose, SecurityLevel};
26 use platform_value::{BinaryData, Identifier};
27 use std::collections::BTreeMap;
28
29 fn sample_with_disabled(disabled_at: Option<u64>) -> IdentityV0 {
30 let mut keys: BTreeMap<u32, IdentityPublicKey> = BTreeMap::new();
31 keys.insert(
32 0,
33 IdentityPublicKey::V0(IdentityPublicKeyV0 {
34 id: 0,
35 purpose: Purpose::AUTHENTICATION,
36 security_level: SecurityLevel::MASTER,
37 contract_bounds: None,
38 key_type: KeyType::ECDSA_SECP256K1,
39 read_only: false,
40 data: BinaryData::new(vec![0x11; 33]),
41 disabled_at,
42 }),
43 );
44 IdentityV0 {
45 id: Identifier::from([0u8; 32]),
46 public_keys: keys,
47 balance: 0,
48 revision: 0,
49 }
50 }
51
52 fn key_map_at_index(value: &Value, index: usize) -> &Vec<(Value, Value)> {
53 let map = value.to_map_ref().expect("map");
54 let pks = map
55 .iter()
56 .find(|(k, _)| k.as_text() == Some("publicKeys"))
57 .map(|(_, v)| v)
58 .expect("publicKeys");
59 let arr = pks.to_array_ref().expect("array");
60 arr[index].to_map_ref().expect("key map")
61 }
62
63 #[test]
64 fn to_cleaned_object_strips_null_disabled_at_from_keys() {
65 let id = sample_with_disabled(None);
66 let cleaned = id.to_cleaned_object().expect("cleaned");
67 let key_map = key_map_at_index(&cleaned, 0);
68 assert!(
69 !key_map
70 .iter()
71 .any(|(k, _)| k.as_text() == Some("disabledAt")),
72 "disabledAt should have been stripped"
73 );
74 }
75
76 #[test]
77 fn to_cleaned_object_preserves_present_disabled_at() {
78 let id = sample_with_disabled(Some(123));
79 let cleaned = id.to_cleaned_object().expect("cleaned");
80 let key_map = key_map_at_index(&cleaned, 0);
81 assert!(key_map
82 .iter()
83 .any(|(k, _)| k.as_text() == Some("disabledAt")));
84 }
85
86 #[test]
87 fn to_object_and_cleaned_are_same_for_empty_keys() {
88 let id = IdentityV0 {
89 id: Identifier::from([1u8; 32]),
90 public_keys: BTreeMap::new(),
91 balance: 1,
92 revision: 2,
93 };
94 let object = id.to_object().expect("to_object");
95 let cleaned = id.to_cleaned_object().expect("cleaned");
96 assert_eq!(object, cleaned);
97 }
98
99 #[test]
108 fn to_object_then_try_from_fails_v0_frozen() {
109 let id = sample_with_disabled(Some(9));
110 let value = id.to_object().unwrap();
111 let result = IdentityV0::try_from(value);
112 assert!(
113 result.is_err(),
114 "V0 to_object -> TryFrom<Value> round-trip is not expected to succeed"
115 );
116 }
117
118 #[test]
119 fn try_from_ref_value_fails_on_to_object_output_v0_frozen() {
120 let id = sample_with_disabled(None);
121 let value = id.to_object().unwrap();
122 let result = IdentityV0::try_from(&value);
123 assert!(result.is_err());
124 }
125}