1use super::nonactivation::*;
2use super::*;
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(deny_unknown_fields)]
6pub struct CandidateExclusiveTarget {
7 pub family: CandidateFamilyId,
8 pub domain: CandidateExclusiveObjectDomain,
9 pub semantic_hash: ObjectHash,
10 pub object: ExactObjectRef,
11}
12
13impl CandidateExclusiveTarget {
14 pub(super) fn validate_semantic(&self, bytes: &[u8]) -> Result<(), RemoteObjectRecordError> {
15 match &self.domain {
16 CandidateExclusiveObjectDomain::CircleBootstrapImage { reference, .. }
17 if bytes.is_empty() && self.semantic_hash == reference.image_hash =>
18 {
19 Ok(())
20 }
21 CandidateExclusiveObjectDomain::CircleBootstrapImage { .. } => {
22 Err(RemoteObjectRecordError::StoredReferenceMismatch)
23 }
24 _ => validate_semantic_hash(self.semantic_hash, bytes),
25 }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30#[serde(rename_all = "snake_case", deny_unknown_fields)]
31pub enum CandidateExclusiveObjectDomain {
32 MergeMembershipEntry {
33 family: CandidateFamilyId,
34 reference: crate::membership::MembershipEntryRef,
35 },
36 MergeMembershipHead {
37 family: CandidateFamilyId,
38 reference: crate::membership::MembershipHeadRef,
39 },
40 MergeMembershipWrappedStoreKey {
41 family: CandidateFamilyId,
42 reference: crate::wrapped_store_key::WrappedStoreKeyRef,
43 },
44 StorePackage {
45 reference: crate::store_commit::StorePackageRef,
46 },
47 CirclePackage {
48 reference: crate::store_commit::CirclePackageRef,
49 },
50 CircleAccessLeaf {
51 family: CandidateFamilyId,
52 circle_id: CircleId,
53 reference: crate::store_commit::CircleAccessLeafObjectRef,
54 },
55 CircleAccessEnvelope {
56 family: CandidateFamilyId,
57 circle_id: CircleId,
58 reference: crate::store_commit::CircleAccessEnvelopeObjectRef,
59 },
60 CircleEpochCloseIntent {
61 family: CandidateFamilyId,
62 circle_id: CircleId,
63 reference: crate::circle_control::CircleEpochCloseIntentRef,
64 },
65 CircleEpochCloseOutcome {
66 family: CandidateFamilyId,
67 circle_id: CircleId,
68 reference: crate::circle_control::CircleEpochCloseOutcomeRef,
69 },
70 CircleEpochCloseCancellation {
71 family: CandidateFamilyId,
72 circle_id: CircleId,
73 reference: crate::circle_control::CircleEpochCloseCancellationRef,
74 },
75 CircleBootstrapImage {
76 family: CandidateFamilyId,
77 circle_id: CircleId,
78 owner_pubkey: String,
79 epoch_id: crate::circle::CircleEpochId,
80 recipient_slot: String,
81 reference: crate::store_commit::SnapshotImageRef,
82 },
83}
84
85impl CandidateExclusiveObjectDomain {
86 pub(super) fn family(&self) -> CandidateFamilyId {
87 match self {
88 Self::MergeMembershipEntry { family, .. }
89 | Self::MergeMembershipHead { family, .. }
90 | Self::MergeMembershipWrappedStoreKey { family, .. } => *family,
91 Self::StorePackage { reference } => reference.candidate_family,
92 Self::CirclePackage { reference } => reference.package.candidate_family,
93 Self::CircleAccessLeaf { family, .. }
94 | Self::CircleAccessEnvelope { family, .. }
95 | Self::CircleEpochCloseIntent { family, .. }
96 | Self::CircleEpochCloseOutcome { family, .. }
97 | Self::CircleEpochCloseCancellation { family, .. }
98 | Self::CircleBootstrapImage { family, .. } => *family,
99 }
100 }
101
102 pub(super) fn object(&self) -> &ExactObjectRef {
103 match self {
104 Self::MergeMembershipEntry { reference, .. } => &reference.object,
105 Self::MergeMembershipHead { reference, .. } => &reference.object,
106 Self::MergeMembershipWrappedStoreKey { reference, .. } => &reference.object,
107 Self::StorePackage { reference } => &reference.object,
108 Self::CirclePackage { reference } => &reference.package.object,
109 Self::CircleAccessLeaf { reference, .. } => &reference.object,
110 Self::CircleAccessEnvelope { reference, .. } => &reference.object,
111 Self::CircleEpochCloseIntent { reference, .. } => &reference.object,
112 Self::CircleEpochCloseOutcome { reference, .. } => &reference.object,
113 Self::CircleEpochCloseCancellation { reference, .. } => &reference.object,
114 Self::CircleBootstrapImage { reference, .. } => &reference.object,
115 }
116 }
117
118 pub fn shared_destination(&self) -> Option<SharedLiveSetObjectDomain> {
119 match self {
120 Self::StorePackage { reference } => Some(SharedLiveSetObjectDomain::StorePackage {
121 reference: reference.clone(),
122 }),
123 Self::CirclePackage { reference } => Some(SharedLiveSetObjectDomain::CirclePackage {
124 reference: reference.clone(),
125 }),
126 Self::CircleBootstrapImage { reference, .. } => {
127 Some(SharedLiveSetObjectDomain::CircleBootstrapImage {
128 reference: reference.clone(),
129 })
130 }
131 Self::MergeMembershipEntry { .. }
132 | Self::MergeMembershipHead { .. }
133 | Self::MergeMembershipWrappedStoreKey { .. }
134 | Self::CircleAccessLeaf { .. }
135 | Self::CircleAccessEnvelope { .. }
136 | Self::CircleEpochCloseIntent { .. }
137 | Self::CircleEpochCloseOutcome { .. }
138 | Self::CircleEpochCloseCancellation { .. } => None,
139 }
140 }
141
142 pub fn retained_destination(&self) -> Option<RetainedAuthorityObjectDomain> {
143 match self {
144 Self::MergeMembershipEntry { reference, .. } => {
145 Some(RetainedAuthorityObjectDomain::MergeMembershipEntry {
146 reference: reference.clone(),
147 })
148 }
149 Self::MergeMembershipHead { reference, .. } => {
150 Some(RetainedAuthorityObjectDomain::MergeMembershipHead {
151 reference: reference.clone(),
152 })
153 }
154 Self::MergeMembershipWrappedStoreKey { reference, .. } => Some(
155 RetainedAuthorityObjectDomain::MergeMembershipWrappedStoreKey {
156 reference: reference.clone(),
157 },
158 ),
159 Self::CircleAccessLeaf {
160 family,
161 circle_id,
162 reference,
163 } => Some(RetainedAuthorityObjectDomain::CircleAccessLeaf {
164 family: *family,
165 circle_id: *circle_id,
166 reference: reference.clone(),
167 }),
168 Self::CircleAccessEnvelope {
169 family,
170 circle_id,
171 reference,
172 } => Some(RetainedAuthorityObjectDomain::CircleAccessEnvelope {
173 family: *family,
174 circle_id: *circle_id,
175 reference: reference.clone(),
176 }),
177 Self::CircleEpochCloseIntent {
178 family,
179 circle_id,
180 reference,
181 } => Some(RetainedAuthorityObjectDomain::CircleEpochCloseIntent {
182 family: *family,
183 circle_id: *circle_id,
184 reference: reference.clone(),
185 }),
186 Self::CircleEpochCloseOutcome {
187 family,
188 circle_id,
189 reference,
190 } => Some(RetainedAuthorityObjectDomain::CircleEpochCloseOutcome {
191 family: *family,
192 circle_id: *circle_id,
193 reference: reference.clone(),
194 }),
195 Self::CircleEpochCloseCancellation {
196 family,
197 circle_id,
198 reference,
199 } => Some(
200 RetainedAuthorityObjectDomain::CircleEpochCloseCancellation {
201 family: *family,
202 circle_id: *circle_id,
203 reference: reference.clone(),
204 },
205 ),
206 Self::StorePackage { .. }
207 | Self::CirclePackage { .. }
208 | Self::CircleBootstrapImage { .. } => None,
209 }
210 }
211}
212
213impl SharedLiveSetObjectDomain {
214 pub(super) fn package_object(&self) -> Result<&ExactObjectRef, RemoteObjectRecordError> {
215 match self {
216 Self::StoredBlob
217 | Self::StoreSnapshotImage { .. }
218 | Self::StoreMembershipRollup { .. }
219 | Self::CircleBootstrapImage { .. } => Err(RemoteObjectRecordError::DomainMismatch),
220 Self::StorePackage { reference } => Ok(&reference.object),
221 Self::CirclePackage { reference } => Ok(&reference.package.object),
222 }
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
227#[serde(deny_unknown_fields)]
228pub struct SharedLiveSetObjectRef {
229 pub domain: SharedLiveSetObjectDomain,
230 pub semantic_hash: ObjectHash,
231 pub object: ExactObjectRef,
232}
233
234impl SharedLiveSetObjectRef {
235 pub(super) fn validate_semantic(&self, bytes: &[u8]) -> Result<(), RemoteObjectRecordError> {
236 match &self.domain {
237 SharedLiveSetObjectDomain::StoreSnapshotImage { reference }
238 if bytes.is_empty()
239 && self.semantic_hash == reference.image_hash
240 && self.object == reference.object =>
241 {
242 Ok(())
243 }
244 SharedLiveSetObjectDomain::StoreSnapshotImage { .. } => {
245 Err(RemoteObjectRecordError::StoredReferenceMismatch)
246 }
247 SharedLiveSetObjectDomain::CircleBootstrapImage { reference }
248 if bytes.is_empty()
249 && self.semantic_hash == reference.image_hash
250 && self.object == reference.object =>
251 {
252 Ok(())
253 }
254 SharedLiveSetObjectDomain::CircleBootstrapImage { .. } => {
255 Err(RemoteObjectRecordError::StoredReferenceMismatch)
256 }
257 SharedLiveSetObjectDomain::StoreMembershipRollup { reference }
260 if bytes.is_empty()
261 && self.semantic_hash == reference.rollup_hash
262 && self.object == reference.object =>
263 {
264 Ok(())
265 }
266 SharedLiveSetObjectDomain::StoreMembershipRollup { .. } => {
267 Err(RemoteObjectRecordError::StoredReferenceMismatch)
268 }
269 _ => validate_semantic_hash(self.semantic_hash, bytes),
270 }
271 }
272}
273
274#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
275#[serde(rename_all = "snake_case", deny_unknown_fields)]
276pub enum SharedLiveSetObjectDomain {
277 StoredBlob,
278 StoreSnapshotImage {
279 reference: crate::store_commit::SnapshotImageRef,
280 },
281 StoreMembershipRollup {
286 reference: crate::store_commit::MembershipRollupRef,
287 },
288 CircleBootstrapImage {
289 reference: crate::store_commit::SnapshotImageRef,
290 },
291 StorePackage {
292 reference: crate::store_commit::StorePackageRef,
293 },
294 CirclePackage {
295 reference: crate::store_commit::CirclePackageRef,
296 },
297}
298
299#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
300#[serde(deny_unknown_fields)]
301pub struct RetainedAuthorityObjectRef {
302 pub domain: RetainedAuthorityObjectDomain,
303 pub semantic_hash: ObjectHash,
304 pub object: ExactObjectRef,
305}
306
307#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
308#[serde(deny_unknown_fields)]
309pub struct ProtocolInertObject {
310 pub identity: RetainedAuthorityObjectRef,
311 pub(crate) former_candidates: Vec<CandidateNonactivation>,
312}
313
314impl ProtocolInertObject {
315 pub(super) fn new(
316 identity: RetainedAuthorityObjectRef,
317 former_candidates: Vec<CandidateNonactivation>,
318 ) -> Result<Self, RemoteObjectRecordError> {
319 let value = Self {
320 identity,
321 former_candidates,
322 };
323 value.validate()?;
324 Ok(value)
325 }
326
327 pub fn object_id(&self) -> ObjectHash {
328 remote_object_id(&self.identity.object)
329 }
330
331 pub fn validate(&self) -> Result<(), RemoteObjectRecordError> {
332 validate_nonactivations(&self.former_candidates)
333 }
334
335 pub fn candidate_nonactivation_proof(
336 &self,
337 candidate: &StoreBatchCommitRef,
338 ) -> Result<Option<&CandidateNonactivationProof>, RemoteObjectRecordError> {
339 self.validate()?;
340 find_nonactivation_proof(&self.former_candidates, candidate)
341 }
342
343 pub fn is_terminal_head_for(
344 &self,
345 candidate: &StoreBatchCommitRef,
346 object: &ExactObjectRef,
347 ) -> Result<bool, RemoteObjectRecordError> {
348 self.validate()?;
349 Ok(self.identity.object == *object
350 && matches!(
351 &self.identity.domain,
352 RetainedAuthorityObjectDomain::DeviceHead { reference, head_commit }
353 if reference.object == *object && head_commit == candidate
354 )
355 && matches!(
356 self.candidate_nonactivation_proof(candidate)?,
357 Some(
358 CandidateNonactivationProof::AuthorExclusion { .. }
359 | CandidateNonactivationProof::MergeMembershipGrantRevocation { .. }
360 )
361 ))
362 }
363}
364
365impl RetainedAuthorityObjectRef {
366 pub(super) fn validate_semantic(&self, bytes: &[u8]) -> Result<(), RemoteObjectRecordError> {
367 validate_semantic_hash(self.semantic_hash, bytes)
368 }
369}
370
371#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
372#[serde(rename_all = "snake_case", deny_unknown_fields)]
373pub enum RetainedAuthorityObjectDomain {
374 Commit {
375 reference: StoreBatchCommitRef,
376 },
377 DeviceHead {
378 reference: crate::store_commit::StoreDeviceHeadRef,
379 head_commit: StoreBatchCommitRef,
384 },
385 Acknowledgement {
386 reference: crate::store_commit::StoreAckRef,
387 },
388 CircleAcknowledgement {
389 reference: CircleAckRef,
390 },
391 MergeMembershipWrappedStoreKey {
392 reference: crate::wrapped_store_key::WrappedStoreKeyRef,
393 },
394 StoreMembershipResolution {
395 reference: crate::membership::StoreMembershipConflictResolutionRef,
396 },
397 MergeMembershipEntry {
398 reference: crate::membership::MembershipEntryRef,
399 },
400 MergeMembershipHead {
401 reference: crate::membership::MembershipHeadRef,
402 },
403 DeviceExclusionProposal {
404 reference: crate::store_commit::StoreDeviceExclusionProposalRef,
405 },
406 DeviceExclusionOutcome {
407 reference: crate::store_commit::StoreDeviceExclusionOutcomeRef,
408 },
409 ReclaimEvidence {
410 reference: crate::reclaim::ReclaimEvidenceRef,
411 },
412 ReclaimAuthorization {
413 reference: crate::reclaim::ReclaimAuthorizationRef,
414 },
415 ReclaimReceipt {
416 reference: crate::reclaim::ReclaimReceiptRef,
417 },
418 CircleAccessLeaf {
419 family: CandidateFamilyId,
420 circle_id: CircleId,
421 reference: crate::store_commit::CircleAccessLeafObjectRef,
422 },
423 CircleAccessEnvelope {
424 family: CandidateFamilyId,
425 circle_id: CircleId,
426 reference: crate::store_commit::CircleAccessEnvelopeObjectRef,
427 },
428 CircleEpochCloseIntent {
429 family: CandidateFamilyId,
430 circle_id: CircleId,
431 reference: crate::circle_control::CircleEpochCloseIntentRef,
432 },
433 CircleEpochCloseOutcome {
434 family: CandidateFamilyId,
435 circle_id: CircleId,
436 reference: crate::circle_control::CircleEpochCloseOutcomeRef,
437 },
438 CircleEpochCloseCancellation {
439 family: CandidateFamilyId,
440 circle_id: CircleId,
441 reference: crate::circle_control::CircleEpochCloseCancellationRef,
442 },
443}