Skip to main content

dpp/data_contract/config/v2/
mod.rs

1use crate::data_contract::config;
2use crate::data_contract::config::moderation::ContractModerationConfig;
3use crate::data_contract::config::v1::{DataContractConfigGettersV1, DataContractConfigV1};
4use crate::data_contract::config::{
5    DataContractConfig, DEFAULT_CONTRACT_CAN_BE_DELETED, DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED,
6    DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY, DEFAULT_CONTRACT_DOCUMENT_MUTABILITY,
7    DEFAULT_CONTRACT_KEEPS_HISTORY, DEFAULT_CONTRACT_MUTABILITY, DEFAULT_SIZED_INTEGER_TYPES,
8};
9use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements;
10#[cfg(feature = "json-conversion")]
11use crate::serialization::json_safe_fields;
12use crate::ProtocolError;
13use bincode::{Decode, DecodeUntrusted, Encode};
14use platform_value::Value;
15use serde::{Deserialize, Serialize};
16use std::collections::BTreeMap;
17
18/// Config V2 (protocol version 14): V1 plus the optional contract moderation declaration.
19///
20/// From protocol version 14 this is the config of every new contract, moderated or not; the
21/// config version follows the platform version, not the config's content.
22#[cfg_attr(feature = "json-conversion", json_safe_fields)]
23#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, DecodeUntrusted)]
24#[serde(rename_all = "camelCase", default)]
25pub struct DataContractConfigV2 {
26    /// Can the contract ever be deleted. If the contract is deleted, so should be all
27    /// documents associated with it.
28    pub can_be_deleted: bool,
29    /// Is the contract mutable. Means that the document definitions can be changed or new
30    /// document definitions can be added to the contract
31    pub readonly: bool,
32    /// Does the contract keep history when the contract itself changes
33    pub keeps_history: bool,
34    /// Do documents in the contract keep history. This is a default for all documents in
35    /// the contract, but can be overridden by the document itself
36    pub documents_keep_history_contract_default: bool,
37    /// Are documents in the contract mutable? This specifies whether the documents can be
38    /// changed. This is a default for all document types in the contract, but can be
39    /// overridden by the document type config.
40    pub documents_mutable_contract_default: bool,
41    /// Can documents in the contract be deleted? This specifies whether the documents can be
42    /// deleted. This is a default for all document types in the contract, but can be
43    /// overridden by the document types itself.
44    pub documents_can_be_deleted_contract_default: bool,
45    /// Encryption key storage requirements
46    pub requires_identity_encryption_bounded_key: Option<StorageKeyRequirements>,
47    /// Decryption key storage requirements
48    pub requires_identity_decryption_bounded_key: Option<StorageKeyRequirements>,
49    /// Use sized integer Rust types for `integer` property type based on validation rules
50    pub sized_integer_types: bool,
51    /// The moderation lists the contract keeps and who edits them, `None` for an unmoderated
52    /// contract.
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub moderation: Option<ContractModerationConfig>,
55}
56
57/// Trait representing getters for `DataContractConfigV2`
58pub trait DataContractConfigGettersV2: DataContractConfigGettersV1 {
59    /// The moderation declaration, `None` for an unmoderated contract (and for every config
60    /// below V2).
61    fn moderation(&self) -> Option<&ContractModerationConfig>;
62}
63
64impl Default for DataContractConfigV2 {
65    fn default() -> Self {
66        DataContractConfigV2 {
67            can_be_deleted: DEFAULT_CONTRACT_CAN_BE_DELETED,
68            readonly: !DEFAULT_CONTRACT_MUTABILITY,
69            keeps_history: DEFAULT_CONTRACT_KEEPS_HISTORY,
70            documents_keep_history_contract_default: DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY,
71            documents_mutable_contract_default: DEFAULT_CONTRACT_DOCUMENT_MUTABILITY,
72            documents_can_be_deleted_contract_default: DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED,
73            requires_identity_encryption_bounded_key: None,
74            requires_identity_decryption_bounded_key: None,
75            sized_integer_types: DEFAULT_SIZED_INTEGER_TYPES,
76            moderation: None,
77        }
78    }
79}
80
81impl DataContractConfigV2 {
82    pub fn default_with_version() -> DataContractConfig {
83        Self::default().into()
84    }
85
86    /// Retrieve contract configuration properties from a contract value map: the V1 properties
87    /// plus the optional `moderation` map.
88    #[inline(always)]
89    pub(super) fn get_contract_configuration_properties_v2(
90        contract: &BTreeMap<String, Value>,
91    ) -> Result<DataContractConfigV2, ProtocolError> {
92        let v1 = DataContractConfigV1::get_contract_configuration_properties_v1(contract)?;
93        let moderation = contract
94            .get(config::property::MODERATION)
95            .filter(|value| !value.is_null())
96            .map(|value| platform_value::from_value::<ContractModerationConfig>(value.clone()))
97            .transpose()?;
98        Ok(DataContractConfigV2 {
99            moderation,
100            ..v1.into()
101        })
102    }
103}
104
105impl From<DataContractConfigV1> for DataContractConfigV2 {
106    fn from(value: DataContractConfigV1) -> Self {
107        DataContractConfigV2 {
108            can_be_deleted: value.can_be_deleted,
109            readonly: value.readonly,
110            keeps_history: value.keeps_history,
111            documents_keep_history_contract_default: value.documents_keep_history_contract_default,
112            documents_mutable_contract_default: value.documents_mutable_contract_default,
113            documents_can_be_deleted_contract_default: value
114                .documents_can_be_deleted_contract_default,
115            requires_identity_encryption_bounded_key: value
116                .requires_identity_encryption_bounded_key,
117            requires_identity_decryption_bounded_key: value
118                .requires_identity_decryption_bounded_key,
119            sized_integer_types: value.sized_integer_types,
120            moderation: None,
121        }
122    }
123}
124
125impl From<DataContractConfigV2> for DataContractConfigV1 {
126    /// Drops the moderation declaration. Only meant for a V2 whose `moderation` is `None`.
127    fn from(value: DataContractConfigV2) -> Self {
128        DataContractConfigV1 {
129            can_be_deleted: value.can_be_deleted,
130            readonly: value.readonly,
131            keeps_history: value.keeps_history,
132            documents_keep_history_contract_default: value.documents_keep_history_contract_default,
133            documents_mutable_contract_default: value.documents_mutable_contract_default,
134            documents_can_be_deleted_contract_default: value
135                .documents_can_be_deleted_contract_default,
136            requires_identity_encryption_bounded_key: value
137                .requires_identity_encryption_bounded_key,
138            requires_identity_decryption_bounded_key: value
139                .requires_identity_decryption_bounded_key,
140            sized_integer_types: value.sized_integer_types,
141        }
142    }
143}