Skip to main content

coven_protocol/remote_object/
domains.rs

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            // Like the images: the bytes went to the provider and were never
258            // kept here, so the record names its reference and nothing else.
259            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    /// The membership rollup a Store snapshot published beside its image.
282    /// Its exact slot belongs to the snapshot metadata candidate, even when
283    /// another candidate carries identical rollup bytes.
284    StoreMembershipRollup {
285        reference: crate::store_commit::MembershipRollupRef,
286    },
287    CircleBootstrapImage {
288        reference: crate::store_commit::SnapshotImageRef,
289    },
290    StorePackage {
291        reference: crate::store_commit::StorePackageRef,
292    },
293    CirclePackage {
294        reference: crate::store_commit::CirclePackageRef,
295    },
296}
297
298#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
299#[serde(deny_unknown_fields)]
300pub struct RetainedAuthorityObjectRef {
301    pub domain: RetainedAuthorityObjectDomain,
302    pub semantic_hash: ObjectHash,
303    pub object: ExactObjectRef,
304}
305
306#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
307#[serde(deny_unknown_fields)]
308pub struct ProtocolInertObject {
309    pub identity: RetainedAuthorityObjectRef,
310    pub(crate) former_candidates: Vec<CandidateNonactivation>,
311}
312
313impl ProtocolInertObject {
314    pub(super) fn new(
315        identity: RetainedAuthorityObjectRef,
316        former_candidates: Vec<CandidateNonactivation>,
317    ) -> Result<Self, RemoteObjectRecordError> {
318        let value = Self {
319            identity,
320            former_candidates,
321        };
322        value.validate()?;
323        Ok(value)
324    }
325
326    pub fn object_id(&self) -> ObjectHash {
327        remote_object_id(&self.identity.object)
328    }
329
330    pub fn validate(&self) -> Result<(), RemoteObjectRecordError> {
331        validate_nonactivations(&self.former_candidates)
332    }
333}
334
335impl RetainedAuthorityObjectRef {
336    pub(super) fn validate_semantic(&self, bytes: &[u8]) -> Result<(), RemoteObjectRecordError> {
337        validate_semantic_hash(self.semantic_hash, bytes)
338    }
339}
340
341#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
342#[serde(rename_all = "snake_case", deny_unknown_fields)]
343pub enum RetainedAuthorityObjectDomain {
344    Commit {
345        reference: StoreBatchCommitRef,
346    },
347    Acknowledgement {
348        reference: crate::store_commit::StoreAckRef,
349    },
350    CircleAcknowledgement {
351        reference: CircleAckRef,
352    },
353    MergeMembershipWrappedStoreKey {
354        reference: crate::wrapped_store_key::WrappedStoreKeyRef,
355    },
356
357    ProviderAccessGrant {
358        reference: crate::provider::StoreMemberProviderAccessGrantRef,
359    },
360    DeviceJoinAbandonment {
361        reference: crate::store_commit::DeviceJoinAbandonmentRef,
362    },
363    DeviceRegistration {
364        reference: crate::store_commit::StoreDeviceRegistrationRef,
365    },
366    MergeMembershipEntry {
367        reference: crate::membership::MembershipEntryRef,
368    },
369    MergeMembershipHead {
370        reference: crate::membership::MembershipHeadRef,
371    },
372    MembershipHeadAcceptance {
373        head: crate::membership::MembershipHeadRef,
374        publication: crate::store_commit::StorePublicationRef,
375    },
376    OwnerPromotionRequestPublication {
377        promotion_id: crate::store_commit::OwnerPromotionId,
378        activation: crate::store_commit::OwnerPromotionRequestActivation,
379    },
380    DeviceExclusionProposal {
381        reference: crate::store_commit::StoreDeviceExclusionProposalRef,
382    },
383    DeviceExclusionOutcome {
384        reference: crate::store_commit::StoreDeviceExclusionOutcomeRef,
385    },
386    ReclaimEvidence {
387        reference: crate::reclaim::ReclaimEvidenceRef,
388    },
389    ReclaimAuthorization {
390        reference: crate::reclaim::ReclaimAuthorizationRef,
391    },
392    ReclaimReceipt {
393        reference: crate::reclaim::ReclaimReceiptRef,
394    },
395    CircleAccessLeaf {
396        family: CandidateFamilyId,
397        circle_id: CircleId,
398        reference: crate::store_commit::CircleAccessLeafObjectRef,
399    },
400    CircleAccessEnvelope {
401        family: CandidateFamilyId,
402        circle_id: CircleId,
403        reference: crate::store_commit::CircleAccessEnvelopeObjectRef,
404    },
405    CircleEpochCloseIntent {
406        family: CandidateFamilyId,
407        circle_id: CircleId,
408        reference: crate::circle_control::CircleEpochCloseIntentRef,
409    },
410    CircleEpochCloseOutcome {
411        family: CandidateFamilyId,
412        circle_id: CircleId,
413        reference: crate::circle_control::CircleEpochCloseOutcomeRef,
414    },
415    CircleEpochCloseCancellation {
416        family: CandidateFamilyId,
417        circle_id: CircleId,
418        reference: crate::circle_control::CircleEpochCloseCancellationRef,
419    },
420}