drive/cache/
system_contracts.rs

1use crate::error::Error;
2use arc_swap::{ArcSwap, Guard};
3use dpp::data_contract::DataContract;
4use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract};
5use platform_version::version::{PlatformVersion, ProtocolVersion};
6use std::sync::Arc;
7
8/// A wrapper around a system [`DataContract`] that tracks its activation version
9/// and allows atomic replacement.
10///
11/// This is used for system data contracts that may be updated over time while
12/// tracking the protocol version from which they are considered active.
13pub struct ActiveSystemDataContract {
14    /// The current active version of the data contract.
15    pub contract: ArcSwap<DataContract>,
16
17    /// The protocol version since which this contract is considered active.
18    #[allow(unused)]
19    pub active_since_protocol_version: ProtocolVersion,
20}
21
22impl ActiveSystemDataContract {
23    /// Atomically replaces the current data contract with a new one.
24    ///
25    /// # Arguments
26    ///
27    /// * `contract` - The new [`DataContract`] to store.
28    pub fn store(&self, contract: DataContract) {
29        self.contract.store(Arc::new(contract));
30    }
31
32    /// Loads the current data contract.
33    ///
34    /// Returns a guard that provides shared access to the current [`DataContract`].
35    /// The guard keeps the contract alive for the duration of the borrow.
36    pub fn load(&self) -> Guard<Arc<DataContract>> {
37        self.contract.load()
38    }
39
40    /// Creates a new [`ActiveSystemDataContract`] with the given contract and activation version.
41    ///
42    /// # Arguments
43    ///
44    /// * `contract` - The initial [`DataContract`] to store.
45    /// * `active_since_protocol_version` - The protocol version from which this contract is considered active.
46    pub fn new(contract: DataContract, active_since_protocol_version: ProtocolVersion) -> Self {
47        ActiveSystemDataContract {
48            contract: ArcSwap::from_pointee(contract),
49            active_since_protocol_version,
50        }
51    }
52}
53
54/// System contracts
55pub struct SystemDataContracts {
56    /// Withdrawal contract
57    withdrawals: ActiveSystemDataContract,
58    /// DPNS contract
59    dpns: ActiveSystemDataContract,
60    /// Dashpay contract
61    dashpay: ActiveSystemDataContract,
62    /// Masternode reward shares contract
63    masternode_reward_shares: ActiveSystemDataContract,
64    /// Token history contract
65    token_history: ActiveSystemDataContract,
66    /// Search contract
67    keyword_search: ActiveSystemDataContract,
68}
69
70impl SystemDataContracts {
71    /// Reload **all** core-protocol system contracts for the supplied platform version,
72    /// atomically replacing the cached copies held in each `ArcSwap`.
73    ///
74    /// Call this after you upgrade `PlatformVersion` (e.g. when a protocol bump
75    /// introduces new schemas for DPNS, Token History, etc.).
76    ///
77    /// # Errors
78    /// Propagates any `Error` returned by `load_system_data_contract`.
79    pub fn reload_system_contracts(&self, platform_version: &PlatformVersion) -> Result<(), Error> {
80        use SystemDataContract::*;
81
82        // 1. Load every contract fresh (fail fast on error).
83        let withdrawals = load_system_data_contract(Withdrawals, platform_version)?;
84        let dpns = load_system_data_contract(DPNS, platform_version)?;
85        let dashpay = load_system_data_contract(Dashpay, platform_version)?;
86        let masternode_reward_shares =
87            load_system_data_contract(MasternodeRewards, platform_version)?;
88        let token_history = load_system_data_contract(TokenHistory, platform_version)?;
89        let keyword_search = load_system_data_contract(KeywordSearch, platform_version)?;
90
91        // 2. Swap the cached Arcs — each swap is lock-free & O(1).
92        self.withdrawals.store(withdrawals);
93        self.dpns.store(dpns);
94        self.dashpay.store(dashpay);
95        self.masternode_reward_shares
96            .store(masternode_reward_shares);
97        self.token_history.store(token_history);
98        self.keyword_search.store(keyword_search);
99
100        Ok(())
101    }
102
103    /// load genesis system contracts
104    pub fn load_genesis_system_contracts() -> Result<Self, Error> {
105        // We should use the version where the contract became active for each data contract
106        Ok(Self {
107            withdrawals: ActiveSystemDataContract::new(
108                load_system_data_contract(
109                    SystemDataContract::Withdrawals,
110                    PlatformVersion::first(),
111                )?,
112                1,
113            ),
114            dpns: ActiveSystemDataContract::new(
115                load_system_data_contract(SystemDataContract::DPNS, PlatformVersion::first())?,
116                1,
117            ),
118            dashpay: ActiveSystemDataContract::new(
119                load_system_data_contract(SystemDataContract::Dashpay, PlatformVersion::first())?,
120                1,
121            ),
122            masternode_reward_shares: ActiveSystemDataContract::new(
123                load_system_data_contract(
124                    SystemDataContract::MasternodeRewards,
125                    PlatformVersion::first(),
126                )?,
127                1,
128            ),
129            token_history: ActiveSystemDataContract::new(
130                load_system_data_contract(
131                    SystemDataContract::TokenHistory,
132                    PlatformVersion::first(),
133                )?,
134                9,
135            ),
136            keyword_search: ActiveSystemDataContract::new(
137                load_system_data_contract(
138                    SystemDataContract::KeywordSearch,
139                    PlatformVersion::first(),
140                )?,
141                9,
142            ),
143        })
144    }
145
146    /// Returns withdrawals contract
147    pub fn load_withdrawals(&self) -> Guard<Arc<DataContract>> {
148        self.withdrawals.load()
149    }
150
151    /// Returns token history contract
152    pub fn load_token_history(&self) -> Guard<Arc<DataContract>> {
153        self.token_history.load()
154    }
155
156    /// Returns DPNS contract
157    pub fn load_dpns(&self) -> Guard<Arc<DataContract>> {
158        self.dpns.load()
159    }
160
161    /// Returns Dashpay contract
162    pub fn load_dashpay(&self) -> Guard<Arc<DataContract>> {
163        self.dashpay.load()
164    }
165
166    /// Returns Masternode reward shares contract
167    pub fn load_masternode_reward_shares(&self) -> Guard<Arc<DataContract>> {
168        self.masternode_reward_shares.load()
169    }
170
171    /// Returns the search contract
172    pub fn load_keyword_search(&self) -> Guard<Arc<DataContract>> {
173        self.keyword_search.load()
174    }
175}