dpp/
system_data_contracts.rs

1use crate::data_contract::DataContractFactory;
2use crate::prelude::*;
3use crate::ProtocolError;
4use std::collections::{BTreeMap, BTreeSet};
5
6use crate::data_contract::accessors::v0::DataContractV0Setters;
7use crate::data_contract::config::v1::DataContractConfigSettersV1;
8use crate::data_contract::config::DataContractConfig;
9pub use data_contracts::*;
10use platform_version::version::PlatformVersion;
11
12pub trait ConfigurationForSystemContract {
13    fn configuration_in_platform_version(
14        &self,
15        version: &PlatformVersion,
16    ) -> Result<DataContractConfig, ProtocolError>;
17}
18
19impl ConfigurationForSystemContract for SystemDataContract {
20    fn configuration_in_platform_version(
21        &self,
22        platform_version: &PlatformVersion,
23    ) -> Result<DataContractConfig, ProtocolError> {
24        match self {
25            SystemDataContract::Withdrawals => {
26                let mut config = DataContractConfig::default_for_version(platform_version)?;
27                config.set_sized_integer_types_enabled(false);
28                Ok(config)
29            }
30            SystemDataContract::MasternodeRewards => {
31                let mut config = DataContractConfig::default_for_version(platform_version)?;
32                config.set_sized_integer_types_enabled(false);
33                Ok(config)
34            }
35            SystemDataContract::FeatureFlags => {
36                let mut config = DataContractConfig::default_for_version(platform_version)?;
37                config.set_sized_integer_types_enabled(false);
38                Ok(config)
39            }
40            SystemDataContract::DPNS => {
41                let mut config = DataContractConfig::default_for_version(platform_version)?;
42                config.set_sized_integer_types_enabled(false);
43                Ok(config)
44            }
45            SystemDataContract::Dashpay => {
46                let mut config = DataContractConfig::default_for_version(platform_version)?;
47                config.set_sized_integer_types_enabled(false);
48                Ok(config)
49            }
50            SystemDataContract::WalletUtils => {
51                let mut config = DataContractConfig::default_for_version(platform_version)?;
52                config.set_sized_integer_types_enabled(false);
53                Ok(config)
54            }
55            SystemDataContract::TokenHistory => {
56                let mut config = DataContractConfig::default_for_version(platform_version)?;
57                config.set_sized_integer_types_enabled(true);
58                Ok(config)
59            }
60            SystemDataContract::KeywordSearch => {
61                let mut config = DataContractConfig::default_for_version(platform_version)?;
62                config.set_sized_integer_types_enabled(true);
63                Ok(config)
64            }
65        }
66    }
67}
68
69fn create_data_contract(
70    factory: &DataContractFactory,
71    system_contract: SystemDataContract,
72    platform_version: &PlatformVersion,
73) -> Result<DataContract, ProtocolError> {
74    let DataContractSource {
75        id_bytes,
76        owner_id_bytes,
77        version,
78        definitions,
79        document_schemas,
80    } = system_contract
81        .source(platform_version)
82        .map_err(|e| ProtocolError::Generic(e.to_string()))?;
83
84    let id = Identifier::from(id_bytes);
85    let owner_id = Identifier::from(owner_id_bytes);
86
87    let mut data_contract = factory.create(
88        owner_id,
89        0,
90        document_schemas.into(),
91        Some(system_contract.configuration_in_platform_version(platform_version)?),
92        definitions.map(|def| def.into()),
93    )?;
94
95    data_contract.data_contract_mut().set_id(id);
96    data_contract.data_contract_mut().set_version(version);
97
98    Ok(data_contract.data_contract_owned())
99}
100
101pub fn load_system_data_contract(
102    system_contract: SystemDataContract,
103    platform_version: &PlatformVersion,
104) -> Result<DataContract, ProtocolError> {
105    let factory = DataContractFactory::new(platform_version.protocol_version)?;
106
107    create_data_contract(&factory, system_contract, platform_version)
108}
109
110pub fn load_system_data_contracts(
111    system_contracts: BTreeSet<SystemDataContract>,
112    platform_version: &PlatformVersion,
113) -> Result<BTreeMap<SystemDataContract, DataContract>, ProtocolError> {
114    let factory = DataContractFactory::new(platform_version.protocol_version)?;
115
116    system_contracts
117        .into_iter()
118        .map(|system_contract| {
119            let data_contract = create_data_contract(&factory, system_contract, platform_version)?;
120
121            Ok((system_contract, data_contract))
122        })
123        .collect()
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129    use crate::data_contract::serialized_version::DataContractInSerializationFormat;
130    use crate::serialization::PlatformSerializableWithPlatformVersion;
131    use platform_version::TryIntoPlatformVersioned;
132    #[test]
133    fn test_load_system_data_contract_v8_vs_v9() {
134        let contract_1 = load_system_data_contract(
135            SystemDataContract::TokenHistory,
136            PlatformVersion::get(8).unwrap(),
137        )
138        .expect("data_contract");
139        let contract_2 = load_system_data_contract(
140            SystemDataContract::TokenHistory,
141            PlatformVersion::get(9).unwrap(),
142        )
143        .expect("data_contract");
144        assert_ne!(contract_1, contract_2);
145    }
146
147    #[test]
148    fn serialize_withdrawal_contract_v1_vs_v9() {
149        let contract_1 = load_system_data_contract(
150            SystemDataContract::Withdrawals,
151            PlatformVersion::get(1).unwrap(),
152        )
153        .expect("data_contract");
154        let contract_2 = load_system_data_contract(
155            SystemDataContract::Withdrawals,
156            PlatformVersion::get(9).unwrap(),
157        )
158        .expect("data_contract");
159
160        assert_ne!(contract_1, contract_2);
161        let v1_ser: DataContractInSerializationFormat = contract_1
162            .clone()
163            .try_into_platform_versioned(PlatformVersion::get(1).unwrap())
164            .expect("expected to serialize");
165        let v2_ser: DataContractInSerializationFormat = contract_2
166            .clone()
167            .try_into_platform_versioned(PlatformVersion::get(1).unwrap())
168            .expect("expected to serialize");
169        assert_eq!(v1_ser, v2_ser);
170
171        let v1_bytes = contract_1
172            .serialize_to_bytes_with_platform_version(PlatformVersion::get(1).unwrap())
173            .expect("expected to serialize");
174        let v8_bytes = contract_1
175            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
176            .expect("expected to serialize");
177        let v9_bytes = contract_1
178            .serialize_to_bytes_with_platform_version(PlatformVersion::get(9).unwrap())
179            .expect("expected to serialize");
180        assert_eq!(v1_bytes.len(), 1747);
181        assert_eq!(v8_bytes.len(), 1747);
182        assert_eq!(v9_bytes.len(), 1757); // this will still use a config v0 without sized_integer_types
183
184        let v1_bytes = contract_2
185            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
186            .expect("expected to serialize");
187        let v8_bytes = contract_2
188            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
189            .expect("expected to serialize");
190        let v9_bytes = contract_2
191            .serialize_to_bytes_with_platform_version(PlatformVersion::get(9).unwrap())
192            .expect("expected to serialize");
193        assert_eq!(v1_bytes.len(), 1747);
194        assert_eq!(v8_bytes.len(), 1747);
195        assert_eq!(v9_bytes.len(), 1758); // this will use a config v1 in serialization with sized_integer_types
196    }
197}