platform_version/version/
protocol_version.rs1use crate::error::PlatformVersionError;
2use crate::version::dpp_versions::DPPVersion;
3use crate::version::drive_abci_versions::DriveAbciVersion;
4use crate::version::drive_versions::DriveVersion;
5use crate::version::fee::FeeVersion;
6#[cfg(feature = "mock-versions")]
7use crate::version::mocks::v2_test::TEST_PLATFORM_V2;
8#[cfg(feature = "mock-versions")]
9use crate::version::mocks::v3_test::TEST_PLATFORM_V3;
10#[cfg(feature = "mock-versions")]
11use crate::version::mocks::TEST_PROTOCOL_VERSION_SHIFT_BYTES;
12use crate::version::system_data_contract_versions::SystemDataContractVersions;
13#[cfg(feature = "mock-versions")]
14use std::sync::OnceLock;
15
16use crate::version::consensus_versions::ConsensusVersions;
17use crate::version::system_limits::SystemLimits;
18
19use crate::version::v1::PLATFORM_V1;
20use crate::version::v10::PLATFORM_V10;
21use crate::version::v11::PLATFORM_V11;
22use crate::version::v12::PLATFORM_V12;
23use crate::version::v13::PLATFORM_V13;
24use crate::version::v14::PLATFORM_V14;
25use crate::version::v2::PLATFORM_V2;
26use crate::version::v3::PLATFORM_V3;
27use crate::version::v4::PLATFORM_V4;
28use crate::version::v5::PLATFORM_V5;
29use crate::version::v6::PLATFORM_V6;
30use crate::version::v7::PLATFORM_V7;
31use crate::version::v8::PLATFORM_V8;
32use crate::version::v9::PLATFORM_V9;
33
34use crate::version::ProtocolVersion;
35pub use versioned_feature_core::*;
36
37#[derive(Clone, Debug)]
38pub struct PlatformVersion {
39 pub protocol_version: ProtocolVersion,
40 pub dpp: DPPVersion,
41 pub drive: DriveVersion,
42 pub drive_abci: DriveAbciVersion,
43 pub consensus: ConsensusVersions,
44 pub fee_version: FeeVersion,
45 pub system_data_contracts: SystemDataContractVersions,
46 pub system_limits: SystemLimits,
47}
48
49pub const PLATFORM_VERSIONS: &[PlatformVersion] = &[
50 PLATFORM_V1,
51 PLATFORM_V2,
52 PLATFORM_V3,
53 PLATFORM_V4,
54 PLATFORM_V5,
55 PLATFORM_V6,
56 PLATFORM_V7,
57 PLATFORM_V8,
58 PLATFORM_V9,
59 PLATFORM_V10,
60 PLATFORM_V11,
61 PLATFORM_V12,
62 PLATFORM_V13,
63 PLATFORM_V14,
64];
65
66#[cfg(feature = "mock-versions")]
67pub static PLATFORM_TEST_VERSIONS: OnceLock<Vec<PlatformVersion>> = OnceLock::new();
69#[cfg(feature = "mock-versions")]
70const DEFAULT_PLATFORM_TEST_VERSIONS: &[PlatformVersion] = &[TEST_PLATFORM_V2, TEST_PLATFORM_V3];
71
72pub const LATEST_PLATFORM_VERSION: &PlatformVersion = &PLATFORM_V14;
73
74pub const DESIRED_PLATFORM_VERSION: &PlatformVersion = LATEST_PLATFORM_VERSION;
75
76impl PlatformVersion {
77 pub fn get<'a>(version: ProtocolVersion) -> Result<&'a Self, PlatformVersionError> {
78 if version > 0 {
79 #[cfg(feature = "mock-versions")]
80 {
81 if version >> TEST_PROTOCOL_VERSION_SHIFT_BYTES > 0 {
82 let test_version = version - (1 << TEST_PROTOCOL_VERSION_SHIFT_BYTES);
83
84 let versions = PLATFORM_TEST_VERSIONS
86 .get_or_init(|| vec![TEST_PLATFORM_V2, TEST_PLATFORM_V3]);
87
88 return versions.get(test_version as usize - 2).ok_or(
89 PlatformVersionError::UnknownVersionError(format!(
90 "no test platform version {test_version}"
91 )),
92 );
93 }
94 }
95 PLATFORM_VERSIONS.get(version as usize - 1).ok_or_else(|| {
96 PlatformVersionError::UnknownVersionError(format!("no platform version {version}"))
97 })
98 } else {
99 Err(PlatformVersionError::UnknownVersionError(format!(
100 "no platform version {version}"
101 )))
102 }
103 }
104
105 pub fn get_optional<'a>(version: ProtocolVersion) -> Option<&'a Self> {
106 if version > 0 {
107 #[cfg(feature = "mock-versions")]
108 {
109 if version >> TEST_PROTOCOL_VERSION_SHIFT_BYTES > 0 {
110 let test_version = version - (1 << TEST_PROTOCOL_VERSION_SHIFT_BYTES);
111
112 let versions = PLATFORM_TEST_VERSIONS
114 .get_or_init(|| vec![TEST_PLATFORM_V2, TEST_PLATFORM_V3]);
115
116 return versions.get(test_version as usize - 2);
117 }
118 }
119 PLATFORM_VERSIONS.get(version as usize - 1)
120 } else {
121 None
122 }
123 }
124
125 pub fn get_version_or_latest<'a>(
126 version: Option<ProtocolVersion>,
127 ) -> Result<&'a Self, PlatformVersionError> {
128 if let Some(version) = version {
129 if version > 0 {
130 #[cfg(feature = "mock-versions")]
131 {
132 if version >> TEST_PROTOCOL_VERSION_SHIFT_BYTES > 0 {
133 let test_version = version - (1 << TEST_PROTOCOL_VERSION_SHIFT_BYTES);
134
135 let versions = PLATFORM_TEST_VERSIONS
137 .get_or_init(|| Vec::from(DEFAULT_PLATFORM_TEST_VERSIONS));
138
139 return versions.get(test_version as usize - 2).ok_or(
140 PlatformVersionError::UnknownVersionError(format!(
141 "no test platform version {test_version}"
142 )),
143 );
144 }
145 }
146 PLATFORM_VERSIONS.get(version as usize - 1).ok_or(
147 PlatformVersionError::UnknownVersionError(format!(
148 "no platform version {version}"
149 )),
150 )
151 } else {
152 Err(PlatformVersionError::UnknownVersionError(format!(
153 "no platform version {version}"
154 )))
155 }
156 } else {
157 Ok(Self::latest())
158 }
159 }
160
161 pub fn first<'a>() -> &'a Self {
162 PLATFORM_VERSIONS
163 .first()
164 .expect("expected to have a platform version")
165 }
166
167 pub fn latest<'a>() -> &'a Self {
168 PLATFORM_VERSIONS
169 .last()
170 .expect("expected to have a platform version")
171 }
172
173 pub fn desired<'a>() -> &'a Self {
174 DESIRED_PLATFORM_VERSION
175 }
176
177 #[cfg(feature = "mock-versions")]
178 pub fn replace_test_versions(versions: Vec<PlatformVersion>) {
180 PLATFORM_TEST_VERSIONS
181 .set(versions)
182 .expect("failed to set test versions")
183 }
184}
185
186#[cfg(test)]
187mod shielded_pool_gating_tests {
188 use super::PlatformVersion;
189
190 #[test]
209 fn shielded_block_processing_methods_inactive_before_v12() {
210 let v11 = PlatformVersion::get(11).expect("protocol version 11 must exist");
211 let block_end = &v11.drive_abci.methods.block_end;
212
213 assert_eq!(
214 block_end.record_shielded_pool_anchor, None,
215 "v11 must NOT record shielded pool anchors: the [52, \"M\"] subtree does not exist before v12"
216 );
217 assert_eq!(
218 block_end.prune_shielded_pool_anchors, None,
219 "v11 must NOT prune shielded pool anchors: the [52, \"M\"] subtree does not exist before v12"
220 );
221 }
222
223 #[test]
224 fn shielded_block_processing_methods_active_at_v12() {
225 let v12 = PlatformVersion::get(12).expect("protocol version 12 must exist");
226 let block_end = &v12.drive_abci.methods.block_end;
227
228 assert_eq!(block_end.record_shielded_pool_anchor, Some(0));
231 assert_eq!(block_end.prune_shielded_pool_anchors, Some(0));
232 }
233
234 #[test]
245 fn shielded_transparent_credit_recording_gated_to_v13() {
246 let v12 = PlatformVersion::get(12).expect("protocol version 12 must exist");
247 let v13 = PlatformVersion::get(13).expect("protocol version 13 must exist");
248 let stp12 = &v12.drive_abci.methods.state_transition_processing;
249 let stp13 = &v13.drive_abci.methods.state_transition_processing;
250
251 assert_eq!(
253 stp12.record_added_balance_outputs, 0,
254 "v12 must use record_added_balance_outputs v0 (drops shielded-spend credits)"
255 );
256 assert_eq!(
257 stp13.record_added_balance_outputs, 1,
258 "v13 must use record_added_balance_outputs v1 (records shielded-spend credits)"
259 );
260
261 assert_eq!(
264 stp12.process_validation_result, 0,
265 "v12 must use process_validation_result v0 (drops paid-invalid balance effects)"
266 );
267 assert_eq!(
268 stp13.process_validation_result, 1,
269 "v13 must use process_validation_result v1 (records paid-invalid balance effects)"
270 );
271
272 assert_eq!(
274 stp12.process_raw_state_transitions, 0,
275 "v12 outer loop stays process_raw_state_transitions v0"
276 );
277 assert_eq!(
278 stp13.process_raw_state_transitions, 0,
279 "v13 must NOT bump the unchanged outer loop"
280 );
281
282 assert_eq!(
285 stp12.store_address_balances_to_recent_block_storage,
286 Some(0),
287 "v12 store method is Some(0)"
288 );
289 assert_eq!(
290 stp13.store_address_balances_to_recent_block_storage,
291 Some(0),
292 "v13 must NOT bump the unchanged store method"
293 );
294 assert_eq!(stp13.cleanup_recent_block_storage_address_balances, Some(0));
296 }
297}