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        }
68    }
69}
70
71fn create_data_contract(
72    factory: &DataContractFactory,
73    system_contract: SystemDataContract,
74    platform_version: &PlatformVersion,
75) -> Result<DataContract, ProtocolError> {
76    let DataContractSource {
77        id_bytes,
78        owner_id_bytes,
79        version,
80        definitions,
81        document_schemas,
82    } = system_contract
83        .source(platform_version)
84        .map_err(|e| ProtocolError::Generic(e.to_string()))?;
85
86    let id = Identifier::from(id_bytes);
87    let owner_id = Identifier::from(owner_id_bytes);
88
89    let mut data_contract = factory.create(
90        owner_id,
91        0,
92        document_schemas.into(),
93        Some(system_contract.configuration_in_platform_version(platform_version)?),
94        definitions.map(|def| def.into()),
95    )?;
96
97    data_contract.data_contract_mut().set_id(id);
98    data_contract.data_contract_mut().set_version(version);
99
100    Ok(data_contract.data_contract_owned())
101}
102
103pub fn load_system_data_contract(
104    system_contract: SystemDataContract,
105    platform_version: &PlatformVersion,
106) -> Result<DataContract, ProtocolError> {
107    let factory = DataContractFactory::new(platform_version.protocol_version)?;
108
109    create_data_contract(&factory, system_contract, platform_version)
110}
111
112pub fn load_system_data_contracts(
113    system_contracts: BTreeSet<SystemDataContract>,
114    platform_version: &PlatformVersion,
115) -> Result<BTreeMap<SystemDataContract, DataContract>, ProtocolError> {
116    let factory = DataContractFactory::new(platform_version.protocol_version)?;
117
118    system_contracts
119        .into_iter()
120        .map(|system_contract| {
121            let data_contract = create_data_contract(&factory, system_contract, platform_version)?;
122
123            Ok((system_contract, data_contract))
124        })
125        .collect()
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use crate::data_contract::serialized_version::DataContractInSerializationFormat;
132    use crate::serialization::PlatformSerializableWithPlatformVersion;
133    use platform_version::TryIntoPlatformVersioned;
134    #[test]
135    fn test_load_system_data_contract_v8_vs_v9() {
136        let contract_1 = load_system_data_contract(
137            SystemDataContract::TokenHistory,
138            PlatformVersion::get(8).unwrap(),
139        )
140        .expect("data_contract");
141        let contract_2 = load_system_data_contract(
142            SystemDataContract::TokenHistory,
143            PlatformVersion::get(9).unwrap(),
144        )
145        .expect("data_contract");
146        assert_ne!(contract_1, contract_2);
147    }
148
149    #[test]
150    fn serialize_withdrawal_contract_v1_vs_v9() {
151        let contract_1 = load_system_data_contract(
152            SystemDataContract::Withdrawals,
153            PlatformVersion::get(1).unwrap(),
154        )
155        .expect("data_contract");
156        let contract_2 = load_system_data_contract(
157            SystemDataContract::Withdrawals,
158            PlatformVersion::get(9).unwrap(),
159        )
160        .expect("data_contract");
161
162        assert_ne!(contract_1, contract_2);
163        let v1_ser: DataContractInSerializationFormat = contract_1
164            .clone()
165            .try_into_platform_versioned(PlatformVersion::get(1).unwrap())
166            .expect("expected to serialize");
167        let v2_ser: DataContractInSerializationFormat = contract_2
168            .clone()
169            .try_into_platform_versioned(PlatformVersion::get(1).unwrap())
170            .expect("expected to serialize");
171        assert_eq!(v1_ser, v2_ser);
172
173        let v1_bytes = contract_1
174            .serialize_to_bytes_with_platform_version(PlatformVersion::get(1).unwrap())
175            .expect("expected to serialize");
176        let v8_bytes = contract_1
177            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
178            .expect("expected to serialize");
179        let v9_bytes = contract_1
180            .serialize_to_bytes_with_platform_version(PlatformVersion::get(9).unwrap())
181            .expect("expected to serialize");
182        assert_eq!(v1_bytes.len(), 1747);
183        assert_eq!(v8_bytes.len(), 1747);
184        assert_eq!(v9_bytes.len(), 1757); // this will still use a config v0 without sized_integer_types
185
186        let v1_bytes = contract_2
187            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
188            .expect("expected to serialize");
189        let v8_bytes = contract_2
190            .serialize_to_bytes_with_platform_version(PlatformVersion::get(8).unwrap())
191            .expect("expected to serialize");
192        let v9_bytes = contract_2
193            .serialize_to_bytes_with_platform_version(PlatformVersion::get(9).unwrap())
194            .expect("expected to serialize");
195        assert_eq!(v1_bytes.len(), 1747);
196        assert_eq!(v8_bytes.len(), 1747);
197        assert_eq!(v9_bytes.len(), 1758); // this will use a config v1 in serialization with sized_integer_types
198    }
199}