Skip to main content

coven_protocol/remote_object/
construction.rs

1use super::ownership::*;
2use super::*;
3
4impl RemoteObjectRecord {
5    fn candidate_exclusive_retained_authority(
6        family: CandidateFamilyId,
7        domain: CandidateExclusiveObjectDomain,
8        canonical_signed_bytes: &[u8],
9        stored_bytes: &[u8],
10        owner: StoreBatchCommitRef,
11    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
12        let object = domain.object().clone();
13        let record = Self::CandidateExclusive(CandidateObjectRecord {
14            identity: CandidateExclusiveTarget {
15                family,
16                domain,
17                semantic_hash: ObjectHash::digest(canonical_signed_bytes),
18                object,
19            },
20            payloads: RemoteObjectPayloads::SpooledInline,
21            state: CandidateObjectState::Prepared {
22                ownership: PendingCandidateOwnership {
23                    pending: BTreeSet::from([owner]),
24                    nonactivated: Vec::new(),
25                },
26            },
27        });
28        record.validate_payload(canonical_signed_bytes)?;
29        ClosedRemoteObject::with_spooled_payloads(record, canonical_signed_bytes, stored_bytes)
30    }
31
32    pub(super) fn candidate_activated_retained_authority(
33        domain: RetainedAuthorityObjectDomain,
34        semantic_hash: ObjectHash,
35        object: ExactObjectRef,
36        canonical_signed_bytes: &[u8],
37        stored_bytes: &[u8],
38        owner: StoreBatchCommitRef,
39    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
40        let record = Self::RetainedAuthority(RetainedAuthorityRecord {
41            identity: RetainedAuthorityObjectRef {
42                domain,
43                semantic_hash,
44                object,
45            },
46            payloads: RemoteObjectPayloads::SpooledInline,
47            state: RetainedAuthorityObjectState::Prepared {
48                ownership: PendingCandidateOwnership {
49                    pending: BTreeSet::from([owner]),
50                    nonactivated: Vec::new(),
51                },
52            },
53        });
54        record.validate_payload(canonical_signed_bytes)?;
55        ClosedRemoteObject::with_spooled_payloads(record, canonical_signed_bytes, stored_bytes)
56    }
57
58    pub fn candidate_commit(
59        identity: StoreBatchCommitRef,
60        canonical_signed_bytes: &[u8],
61        stored_bytes: &[u8],
62    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
63        let record = Self::CandidateCommit(CandidateCommitRecord {
64            identity,
65            semantic_hash: ObjectHash::digest(canonical_signed_bytes),
66            payloads: RemoteObjectPayloads::SpooledInline,
67            state: CandidateCommitState::Prepared,
68        });
69        record.validate_payload(canonical_signed_bytes)?;
70        ClosedRemoteObject::with_spooled_payloads(record, canonical_signed_bytes, stored_bytes)
71    }
72
73    pub fn candidate_activated_store_head(
74        reference: crate::store_commit::StoreDeviceHeadRef,
75        canonical_signed_bytes: &[u8],
76        stored_bytes: &[u8],
77        owner: StoreBatchCommitRef,
78    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
79        let object = reference.object.clone();
80        // The head names the commit it publishes; reading it out here is the
81        // one parse, and the record carries the answer from then on.
82        let head: crate::store_commit::StoreDeviceHead =
83            serde_json::from_slice(canonical_signed_bytes)?;
84        Self::candidate_activated_retained_authority(
85            RetainedAuthorityObjectDomain::DeviceHead {
86                reference,
87                head_commit: head.commit.clone(),
88            },
89            ObjectHash::digest(canonical_signed_bytes),
90            object,
91            canonical_signed_bytes,
92            stored_bytes,
93            owner,
94        )
95    }
96
97    pub(crate) fn candidate_activated_store_acknowledgement(
98        reference: crate::store_commit::StoreAckRef,
99        canonical_signed_bytes: &[u8],
100        stored_bytes: &[u8],
101        owner: StoreBatchCommitRef,
102    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
103        let object = reference.object.clone();
104        Self::candidate_activated_retained_authority(
105            RetainedAuthorityObjectDomain::Acknowledgement { reference },
106            ObjectHash::digest(canonical_signed_bytes),
107            object,
108            canonical_signed_bytes,
109            stored_bytes,
110            owner,
111        )
112    }
113
114    pub(crate) fn candidate_activated_circle_acknowledgement(
115        reference: CircleAckRef,
116        canonical_semantic_bytes: &[u8],
117        stored_bytes: &[u8],
118        owner: StoreBatchCommitRef,
119    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
120        let object = reference.object.clone();
121        Self::candidate_activated_retained_authority(
122            RetainedAuthorityObjectDomain::CircleAcknowledgement { reference },
123            ObjectHash::digest(canonical_semantic_bytes),
124            object,
125            canonical_semantic_bytes,
126            stored_bytes,
127            owner,
128        )
129    }
130
131    pub fn candidate_activated_store_membership_resolution(
132        reference: crate::membership::StoreMembershipConflictResolutionRef,
133        canonical_semantic_bytes: &[u8],
134        stored_bytes: &[u8],
135        candidate: StoreBatchCommitRef,
136    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
137        let semantic_hash = ObjectHash::digest(canonical_semantic_bytes);
138        let object = reference.object.clone();
139        Self::candidate_activated_retained_authority(
140            RetainedAuthorityObjectDomain::StoreMembershipResolution { reference },
141            semantic_hash,
142            object,
143            canonical_semantic_bytes,
144            stored_bytes,
145            candidate,
146        )
147    }
148
149    pub fn candidate_exclusive_merge_membership_entry(
150        family: CandidateFamilyId,
151        reference: crate::membership::MembershipEntryRef,
152        canonical_signed_bytes: &[u8],
153        stored_bytes: &[u8],
154        owner: StoreBatchCommitRef,
155    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
156        Self::candidate_exclusive_retained_authority(
157            family,
158            CandidateExclusiveObjectDomain::MergeMembershipEntry { family, reference },
159            canonical_signed_bytes,
160            stored_bytes,
161            owner,
162        )
163    }
164
165    pub fn candidate_exclusive_merge_membership_head(
166        family: CandidateFamilyId,
167        reference: crate::membership::MembershipHeadRef,
168        canonical_signed_bytes: &[u8],
169        stored_bytes: &[u8],
170        owner: StoreBatchCommitRef,
171    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
172        Self::candidate_exclusive_retained_authority(
173            family,
174            CandidateExclusiveObjectDomain::MergeMembershipHead { family, reference },
175            canonical_signed_bytes,
176            stored_bytes,
177            owner,
178        )
179    }
180
181    pub(crate) fn candidate_exclusive_merge_membership_wrapped_store_key(
182        family: CandidateFamilyId,
183        reference: crate::wrapped_store_key::WrappedStoreKeyRef,
184        canonical_signed_bytes: &[u8],
185        stored_bytes: &[u8],
186        owner: StoreBatchCommitRef,
187    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
188        Self::candidate_exclusive_retained_authority(
189            family,
190            CandidateExclusiveObjectDomain::MergeMembershipWrappedStoreKey { family, reference },
191            canonical_signed_bytes,
192            stored_bytes,
193            owner,
194        )
195    }
196
197    pub(crate) fn candidate_activated_device_exclusion_proposal(
198        reference: crate::store_commit::StoreDeviceExclusionProposalRef,
199        canonical_signed_bytes: &[u8],
200        stored_bytes: &[u8],
201        owner: StoreBatchCommitRef,
202    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
203        let object = reference.object.clone();
204        let semantic_hash = ObjectHash::digest(canonical_signed_bytes);
205        Self::candidate_activated_retained_authority(
206            RetainedAuthorityObjectDomain::DeviceExclusionProposal { reference },
207            semantic_hash,
208            object,
209            canonical_signed_bytes,
210            stored_bytes,
211            owner,
212        )
213    }
214
215    pub(crate) fn candidate_activated_device_exclusion_outcome(
216        reference: crate::store_commit::StoreDeviceExclusionOutcomeRef,
217        canonical_signed_bytes: &[u8],
218        stored_bytes: &[u8],
219        owner: StoreBatchCommitRef,
220    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
221        let object = reference.object().clone();
222        let semantic_hash = ObjectHash::digest(canonical_signed_bytes);
223        Self::candidate_activated_retained_authority(
224            RetainedAuthorityObjectDomain::DeviceExclusionOutcome { reference },
225            semantic_hash,
226            object,
227            canonical_signed_bytes,
228            stored_bytes,
229            owner,
230        )
231    }
232
233    pub fn candidate_activated_reclaim_evidence(
234        reference: crate::reclaim::ReclaimEvidenceRef,
235        canonical_signed_bytes: &[u8],
236        stored_bytes: &[u8],
237        owner: StoreBatchCommitRef,
238    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
239        let object = reference.object.clone();
240        Self::candidate_activated_retained_authority(
241            RetainedAuthorityObjectDomain::ReclaimEvidence { reference },
242            ObjectHash::digest(canonical_signed_bytes),
243            object,
244            canonical_signed_bytes,
245            stored_bytes,
246            owner,
247        )
248    }
249
250    pub fn candidate_activated_reclaim_authorization(
251        reference: crate::reclaim::ReclaimAuthorizationRef,
252        canonical_signed_bytes: &[u8],
253        stored_bytes: &[u8],
254        owner: StoreBatchCommitRef,
255    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
256        let object = reference.object.clone();
257        Self::candidate_activated_retained_authority(
258            RetainedAuthorityObjectDomain::ReclaimAuthorization { reference },
259            ObjectHash::digest(canonical_signed_bytes),
260            object,
261            canonical_signed_bytes,
262            stored_bytes,
263            owner,
264        )
265    }
266
267    pub fn candidate_activated_reclaim_receipt(
268        reference: crate::reclaim::ReclaimReceiptRef,
269        canonical_signed_bytes: &[u8],
270        stored_bytes: &[u8],
271        owner: StoreBatchCommitRef,
272    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
273        let object = reference.object.clone();
274        Self::candidate_activated_retained_authority(
275            RetainedAuthorityObjectDomain::ReclaimReceipt { reference },
276            ObjectHash::digest(canonical_signed_bytes),
277            object,
278            canonical_signed_bytes,
279            stored_bytes,
280            owner,
281        )
282    }
283
284    pub fn snapshot_activated_blob(
285        stored: &crate::blob::locator::StoredBlobRef,
286        owner: SnapshotObjectOwner,
287    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
288        let locator_bytes = stored.locator().to_bytes();
289        let record = Self::SharedLiveSet(SharedObjectRecord {
290            identity: SharedLiveSetObjectRef {
291                domain: SharedLiveSetObjectDomain::StoredBlob,
292                semantic_hash: ObjectHash::digest(&locator_bytes),
293                object: stored.object().clone(),
294            },
295            payloads: RemoteObjectPayloads::RowBlob { locator_bytes },
296            state: OwnedObjectState::UploadedVerified {
297                ownership: SharedObjectOwnership {
298                    pending: BTreeSet::new(),
299                    activated: BTreeSet::from([SharedObjectOwner::Snapshot(owner)]),
300                    nonactivated: Vec::new(),
301                },
302            },
303        });
304        ClosedRemoteObject::carried(record)
305    }
306
307    pub fn snapshot_activated_image(
308        image: &crate::store_commit::SnapshotImageRef,
309        owner: SnapshotObjectOwner,
310    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
311        let record = Self::SharedLiveSet(SharedObjectRecord {
312            identity: SharedLiveSetObjectRef {
313                domain: SharedLiveSetObjectDomain::StoreSnapshotImage {
314                    reference: image.clone(),
315                },
316                semantic_hash: image.image_hash,
317                object: image.object.clone(),
318            },
319            payloads: RemoteObjectPayloads::SpooledExternal,
320            state: OwnedObjectState::UploadedVerified {
321                ownership: SharedObjectOwnership {
322                    pending: BTreeSet::new(),
323                    activated: BTreeSet::from([SharedObjectOwner::Snapshot(owner)]),
324                    nonactivated: Vec::new(),
325                },
326            },
327        });
328        ClosedRemoteObject::carried(record)
329    }
330
331    /// The membership rollup one snapshot generation published, owned by that
332    /// generation.
333    ///
334    /// The same owner shape the image gets, and for a reason the image does not
335    /// have: a rollup is content-addressed over the membership frontier, so two
336    /// generations published over an unchanged membership name the *same*
337    /// object. Ownership is what keeps the older generation's reclaim from
338    /// deleting the rollup the newer one still points at.
339    pub fn snapshot_activated_membership_rollup(
340        rollup: &crate::store_commit::MembershipRollupRef,
341        owner: SnapshotObjectOwner,
342    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
343        let record = Self::SharedLiveSet(SharedObjectRecord {
344            identity: SharedLiveSetObjectRef {
345                domain: SharedLiveSetObjectDomain::StoreMembershipRollup {
346                    reference: rollup.clone(),
347                },
348                semantic_hash: rollup.rollup_hash,
349                object: rollup.object.clone(),
350            },
351            payloads: RemoteObjectPayloads::SpooledExternal,
352            state: OwnedObjectState::UploadedVerified {
353                ownership: SharedObjectOwnership {
354                    pending: BTreeSet::new(),
355                    activated: BTreeSet::from([SharedObjectOwner::Snapshot(owner)]),
356                    nonactivated: Vec::new(),
357                },
358            },
359        });
360        ClosedRemoteObject::carried(record)
361    }
362
363    pub fn activated_external_package(
364        domain: SharedLiveSetObjectDomain,
365        package: &crate::audience_package::AudiencePackage,
366        owner: StoreBatchCommitRef,
367    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
368        if !matches!(
369            domain,
370            SharedLiveSetObjectDomain::StorePackage { .. }
371                | SharedLiveSetObjectDomain::CirclePackage { .. }
372        ) {
373            return Err(RemoteObjectRecordError::DomainMismatch);
374        }
375        let canonical_semantic_bytes = package.to_bytes();
376        let object = domain.package_object()?.clone();
377        let record = Self::SharedLiveSet(SharedObjectRecord {
378            identity: SharedLiveSetObjectRef {
379                domain,
380                semantic_hash: ObjectHash::digest(&canonical_semantic_bytes),
381                object,
382            },
383            payloads: RemoteObjectPayloads::SpooledExternal,
384            state: OwnedObjectState::UploadedVerified {
385                ownership: SharedObjectOwnership {
386                    pending: BTreeSet::new(),
387                    activated: BTreeSet::from([SharedObjectOwner::StoreCommit(owner)]),
388                    nonactivated: Vec::new(),
389                },
390            },
391        });
392        record.validate_payload(&canonical_semantic_bytes)?;
393        let hash = ObjectHash::digest(&canonical_semantic_bytes);
394        ClosedRemoteObject::with_payloads(
395            record,
396            BTreeMap::from([(hash, canonical_semantic_bytes)]),
397        )
398    }
399
400    pub fn activated_blob(
401        stored: &crate::blob::locator::StoredBlobRef,
402        owner: StoreBatchCommitRef,
403    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
404        let locator_bytes = stored.locator().to_bytes();
405        let record = Self::SharedLiveSet(SharedObjectRecord {
406            identity: SharedLiveSetObjectRef {
407                domain: SharedLiveSetObjectDomain::StoredBlob,
408                semantic_hash: ObjectHash::digest(&locator_bytes),
409                object: stored.object().clone(),
410            },
411            payloads: RemoteObjectPayloads::RowBlob { locator_bytes },
412            state: OwnedObjectState::UploadedVerified {
413                ownership: SharedObjectOwnership {
414                    pending: BTreeSet::new(),
415                    activated: BTreeSet::from([SharedObjectOwner::StoreCommit(owner)]),
416                    nonactivated: Vec::new(),
417                },
418            },
419        });
420        ClosedRemoteObject::carried(record)
421    }
422
423    pub fn candidate_owned_blob(
424        stored: &crate::blob::locator::StoredBlobRef,
425        owner: StoreBatchCommitRef,
426        uploaded_verified: bool,
427    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
428        let locator_bytes = stored.locator().to_bytes();
429        let ownership = PendingCandidateOwnership {
430            pending: BTreeSet::from([owner]),
431            nonactivated: Vec::new(),
432        };
433        let state = if uploaded_verified {
434            OwnedObjectState::UploadedVerified {
435                ownership: SharedObjectOwnership {
436                    pending: ownership.pending,
437                    activated: BTreeSet::new(),
438                    nonactivated: ownership.nonactivated,
439                },
440            }
441        } else {
442            OwnedObjectState::Prepared { ownership }
443        };
444        let record = Self::SharedLiveSet(SharedObjectRecord {
445            identity: SharedLiveSetObjectRef {
446                domain: SharedLiveSetObjectDomain::StoredBlob,
447                semantic_hash: ObjectHash::digest(&locator_bytes),
448                object: stored.object().clone(),
449            },
450            payloads: RemoteObjectPayloads::RowBlob { locator_bytes },
451            state,
452        });
453        ClosedRemoteObject::carried(record)
454    }
455}