Skip to main content

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            // Reserved slot with no implementation. Any caller that reaches here
36            // has a bug (they should have short-circuited on `source()` returning
37            // `ContractReserved`). Return a harmless default config rather than
38            // panicking so this failure mode stays non-fatal.
39            SystemDataContract::FeatureFlags => {
40                DataContractConfig::default_for_version(platform_version)
41            }
42            SystemDataContract::DPNS => {
43                let mut config = DataContractConfig::default_for_version(platform_version)?;
44                config.set_sized_integer_types_enabled(false);
45                Ok(config)
46            }
47            SystemDataContract::Dashpay => {
48                let mut config = DataContractConfig::default_for_version(platform_version)?;
49                config.set_sized_integer_types_enabled(false);
50                Ok(config)
51            }
52            SystemDataContract::WalletUtils => {
53                let mut config = DataContractConfig::default_for_version(platform_version)?;
54                config.set_sized_integer_types_enabled(false);
55                Ok(config)
56            }
57            SystemDataContract::TokenHistory => {
58                let mut config = DataContractConfig::default_for_version(platform_version)?;
59                config.set_sized_integer_types_enabled(true);
60                Ok(config)
61            }
62            SystemDataContract::KeywordSearch => {
63                let mut config = DataContractConfig::default_for_version(platform_version)?;
64                config.set_sized_integer_types_enabled(true);
65                Ok(config)
66            }
67            SystemDataContract::DocumentHistory => {
68                let mut config = DataContractConfig::default_for_version(platform_version)?;
69                config.set_sized_integer_types_enabled(true);
70                Ok(config)
71            }
72        }
73    }
74}
75
76fn create_data_contract(
77    factory: &DataContractFactory,
78    system_contract: SystemDataContract,
79    platform_version: &PlatformVersion,
80) -> Result<DataContract, ProtocolError> {
81    let DataContractSource {
82        id_bytes,
83        owner_id_bytes,
84        version,
85        definitions,
86        document_schemas,
87    } = system_contract
88        .source(platform_version)
89        .map_err(|e| ProtocolError::Generic(e.to_string()))?;
90
91    let id = Identifier::from(id_bytes);
92    let owner_id = Identifier::from(owner_id_bytes);
93
94    let mut data_contract = factory.create(
95        owner_id,
96        0,
97        document_schemas.into(),
98        Some(system_contract.configuration_in_platform_version(platform_version)?),
99        definitions.map(|def| def.into()),
100    )?;
101
102    data_contract.data_contract_mut().set_id(id);
103    data_contract.data_contract_mut().set_version(version);
104
105    Ok(data_contract.data_contract_owned())
106}
107
108pub fn load_system_data_contract(
109    system_contract: SystemDataContract,
110    platform_version: &PlatformVersion,
111) -> Result<DataContract, ProtocolError> {
112    let factory = DataContractFactory::new(platform_version.protocol_version)?;
113
114    create_data_contract(&factory, system_contract, platform_version)
115}
116
117pub fn load_system_data_contracts(
118    system_contracts: BTreeSet<SystemDataContract>,
119    platform_version: &PlatformVersion,
120) -> Result<BTreeMap<SystemDataContract, DataContract>, ProtocolError> {
121    let factory = DataContractFactory::new(platform_version.protocol_version)?;
122
123    system_contracts
124        .into_iter()
125        .map(|system_contract| {
126            let data_contract = create_data_contract(&factory, system_contract, platform_version)?;
127
128            Ok((system_contract, data_contract))
129        })
130        .collect()
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use crate::data_contract::serialized_version::DataContractInSerializationFormat;
137    use crate::serialization::PlatformSerializableWithPlatformVersion;
138    use platform_version::TryIntoPlatformVersioned;
139    #[test]
140    fn test_load_system_data_contract_v8_vs_v9() {
141        let contract_1 = load_system_data_contract(
142            SystemDataContract::TokenHistory,
143            PlatformVersion::get(8).unwrap(),
144        )
145        .expect("data_contract");
146        let contract_2 = load_system_data_contract(
147            SystemDataContract::TokenHistory,
148            PlatformVersion::get(9).unwrap(),
149        )
150        .expect("data_contract");
151        assert_ne!(contract_1, contract_2);
152    }
153
154    #[test]
155    fn serialize_withdrawal_contract_v1_vs_v9() {
156        let contract_1 = load_system_data_contract(
157            SystemDataContract::Withdrawals,
158            PlatformVersion::get(1).unwrap(),
159        )
160        .expect("data_contract");
161        let contract_2 = load_system_data_contract(
162            SystemDataContract::Withdrawals,
163            PlatformVersion::get(9).unwrap(),
164        )
165        .expect("data_contract");
166
167        assert_ne!(contract_1, contract_2);
168        let v1_ser: DataContractInSerializationFormat = contract_1
169            .clone()
170            .try_into_platform_versioned(PlatformVersion::get(1).unwrap())
171            .expect("expected to serialize");
172        let v2_ser: DataContractInSerializationFormat = contract_2
173            .clone()
174            .try_into_platform_versioned(PlatformVersion::get(1).unwrap())
175            .expect("expected to serialize");
176        assert_eq!(v1_ser, v2_ser);
177
178        let v1_bytes = contract_1
179            .serialize_to_bytes_with_platform_version(PlatformVersion::get(1).unwrap())
180            .expect("expected to serialize");
181        let v8_bytes = contract_1
182            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
183            .expect("expected to serialize");
184        let v9_bytes = contract_1
185            .serialize_to_bytes_with_platform_version(PlatformVersion::get(9).unwrap())
186            .expect("expected to serialize");
187        assert_eq!(v1_bytes.len(), 1747);
188        assert_eq!(v8_bytes.len(), 1747);
189        assert_eq!(v9_bytes.len(), 1757); // this will still use a config v0 without sized_integer_types
190
191        let v1_bytes = contract_2
192            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
193            .expect("expected to serialize");
194        let v8_bytes = contract_2
195            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
196            .expect("expected to serialize");
197        let v9_bytes = contract_2
198            .serialize_to_bytes_with_platform_version(PlatformVersion::get(9).unwrap())
199            .expect("expected to serialize");
200        assert_eq!(v1_bytes.len(), 1747);
201        assert_eq!(v8_bytes.len(), 1747);
202        assert_eq!(v9_bytes.len(), 1758); // this will use a config v1 in serialization with sized_integer_types
203    }
204}