dpp/identity/
identity.rs

1use crate::address_funds::PlatformAddress;
2use crate::identity::v0::IdentityV0;
3use crate::identity::{IdentityPublicKey, KeyID};
4use crate::prelude::{AddressNonce, Revision};
5#[cfg(feature = "json-conversion")]
6use crate::serialization::json_safe_fields;
7#[cfg(feature = "value-conversion")]
8use crate::serialization::ValueConvertible;
9
10#[cfg(feature = "identity-hashing")]
11use crate::serialization::PlatformSerializable;
12#[cfg(feature = "identity-hashing")]
13use crate::util::hash;
14use crate::version::PlatformVersion;
15
16use crate::ProtocolError;
17#[cfg(feature = "identity-serialization")]
18use bincode::{Decode, Encode};
19use derive_more::From;
20#[cfg(feature = "identity-serialization")]
21use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
22use platform_value::Identifier;
23
24use crate::fee::Credits;
25use std::collections::{BTreeMap, BTreeSet};
26
27/// The identity is not stored inside of drive, because of this, the serialization is mainly for
28/// transport, the serialization of the identity will include the version, so no passthrough or
29/// untagged is needed here
30#[derive(Debug, Clone, PartialEq, From)]
31#[cfg_attr(
32   any( feature = "serde-conversion" ,feature = "serde-conversion",),
33    derive(serde::Serialize, serde::Deserialize),
34    serde(tag = "$formatVersion"),
35    // platform_version_path("dpp.identity_versions.identity_structure_version")
36)]
37#[cfg_attr(
38    feature = "identity-serialization",
39    derive(Encode, Decode, PlatformDeserialize, PlatformSerialize),
40    platform_serialize(limit = 15000, unversioned)
41)]
42#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
43pub enum Identity {
44    #[cfg_attr(
45        any(feature = "serde-conversion", feature = "serde-conversion"),
46        serde(rename = "0")
47    )]
48    V0(IdentityV0),
49}
50
51/// An identity struct that represent partially set/loaded identity data.
52#[cfg_attr(feature = "json-conversion", json_safe_fields)]
53#[derive(Debug, Clone, Eq, PartialEq)]
54#[cfg_attr(
55    any(feature = "serde-conversion", feature = "serde-conversion",),
56    derive(serde::Serialize, serde::Deserialize),
57    serde(rename_all = "camelCase")
58)]
59pub struct PartialIdentity {
60    pub id: Identifier,
61    pub loaded_public_keys: BTreeMap<KeyID, IdentityPublicKey>,
62    pub balance: Option<Credits>,
63    pub revision: Option<Revision>,
64    /// These are keys that were requested but didn't exist
65    pub not_found_public_keys: BTreeSet<KeyID>,
66}
67
68impl Identity {
69    #[cfg(feature = "identity-hashing")]
70    /// Computes the hash of an identity
71    pub fn hash(&self) -> Result<Vec<u8>, ProtocolError> {
72        Ok(hash::hash_double_to_vec(
73            PlatformSerializable::serialize_to_bytes(self)?,
74        ))
75    }
76
77    pub fn default_versioned(
78        platform_version: &PlatformVersion,
79    ) -> Result<Identity, ProtocolError> {
80        match platform_version
81            .dpp
82            .identity_versions
83            .identity_structure_version
84        {
85            0 => Ok(Identity::V0(IdentityV0::default())),
86            version => Err(ProtocolError::UnknownVersionMismatch {
87                method: "Identity::default_versioned".to_string(),
88                known_versions: vec![0],
89                received: version,
90            }),
91        }
92    }
93
94    /// Created a new identity based on asset locks and keys
95    pub fn new_with_id_and_keys(
96        id: Identifier,
97        public_keys: BTreeMap<KeyID, IdentityPublicKey>,
98        platform_version: &PlatformVersion,
99    ) -> Result<Identity, ProtocolError> {
100        match platform_version
101            .dpp
102            .identity_versions
103            .identity_structure_version
104        {
105            0 => {
106                let identity_v0 = IdentityV0 {
107                    id,
108                    public_keys,
109                    balance: 0,
110                    revision: 0,
111                };
112                Ok(identity_v0.into())
113            }
114            version => Err(ProtocolError::UnknownVersionMismatch {
115                method: "Identity::new_with_id_and_keys".to_string(),
116                known_versions: vec![0],
117                received: version,
118            }),
119        }
120    }
121
122    /// Create a new identity using input [PlatformAddress]es.
123    ///
124    /// This function derives the identity ID from the provided input addresses.
125    ///
126    /// ## Arguments
127    ///
128    /// * `inputs` - A map of `PlatformAddress` to `(AddressNonce, Credits)`.
129    ///   The identity id is derived from the addresses and nonces (credits are ignored for the id derivation).
130    ///   The nonces should represent state after creation of the identity (e.g. be incremented by 1).
131    /// * `public_keys` - A map of KeyID to IdentityPublicKey tuples representing the public keys for the identity.
132    /// * `platform_version` - The platform version to use for identity creation.
133    ///
134    /// ## Returns
135    ///
136    /// * `Result<Identity, ProtocolError>` - Returns the newly created Identity or a ProtocolError if the operation fails.
137    #[cfg(feature = "state-transitions")]
138    pub fn new_with_input_addresses_and_keys(
139        inputs: &BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
140        public_keys: BTreeMap<KeyID, IdentityPublicKey>,
141        platform_version: &PlatformVersion,
142    ) -> Result<Identity, ProtocolError> {
143        use crate::state_transition::identity_id_from_input_addresses;
144
145        let identity_id = identity_id_from_input_addresses(inputs)?;
146        Self::new_with_id_and_keys(identity_id, public_keys, platform_version)
147    }
148
149    /// Convenience method to get Partial Identity Info
150    pub fn into_partial_identity_info(self) -> PartialIdentity {
151        match self {
152            Identity::V0(v0) => v0.into_partial_identity_info(),
153        }
154    }
155
156    /// Convenience method to get Partial Identity Info
157    pub fn into_partial_identity_info_no_balance(self) -> PartialIdentity {
158        match self {
159            Identity::V0(v0) => v0.into_partial_identity_info_no_balance(),
160        }
161    }
162}