Skip to main content

coven_protocol/remote_object/
construction.rs

1use super::ownership::*;
2use super::*;
3
4impl RemoteObjectRecord {
5    pub fn prepared_owner_promotion_request_publication(
6        publication: &crate::store_commit::RetainedOwnerPromotionRequestPublication,
7        commit: &crate::store_commit::StoreBatchCommit,
8    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
9        publication.validate_for(commit)?;
10        let request = commit
11            .owner_promotion_request()
12            .ok_or(RemoteObjectRecordError::DomainMismatch)?;
13        let bytes = publication.value.to_bytes();
14        Self::candidate_activated_retained_authority(
15            RetainedAuthorityObjectDomain::OwnerPromotionRequestPublication {
16                promotion_id: request.promotion_id,
17                activation: publication.value.body().clone(),
18            },
19            ObjectHash::digest(&bytes),
20            publication.object.clone(),
21            &bytes,
22            &bytes,
23            publication.value.commit.clone(),
24        )
25    }
26
27    pub fn prepared_membership_head_acceptance(
28        value: &crate::membership::MembershipHeadAcceptance,
29        head: &crate::membership::AuthorHead,
30        prepared: &crate::objects::PreparedExactObject,
31    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
32        let crate::membership::MembershipHeadActivation::StoreCommit {
33            commit,
34            acceptance_slot,
35        } = &head.activation
36        else {
37            return Err(RemoteObjectRecordError::DomainMismatch);
38        };
39        if value.head.head_hash != head.head_hash()
40            || value.head.coord != head.entry_coord()
41            || prepared.reference().slot() != acceptance_slot
42        {
43            return Err(RemoteObjectRecordError::StoredReferenceMismatch);
44        }
45        let bytes = value.to_bytes();
46        Self::candidate_activated_retained_authority(
47            RetainedAuthorityObjectDomain::MembershipHeadAcceptance {
48                head: value.head.clone(),
49                publication: value.publication()?.clone(),
50            },
51            ObjectHash::digest(&bytes),
52            prepared.reference().clone(),
53            &bytes,
54            prepared.stored_bytes(),
55            commit.clone(),
56        )
57    }
58
59    fn candidate_exclusive_retained_authority(
60        family: CandidateFamilyId,
61        domain: CandidateExclusiveObjectDomain,
62        canonical_signed_bytes: &[u8],
63        stored_bytes: &[u8],
64        owner: StoreBatchCommitRef,
65    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
66        let object = domain.object().clone();
67        let record = Self::CandidateExclusive(CandidateObjectRecord {
68            identity: CandidateExclusiveTarget {
69                family,
70                domain,
71                semantic_hash: ObjectHash::digest(canonical_signed_bytes),
72                object,
73            },
74            payloads: RemoteObjectPayloads::SpooledInline,
75            state: CandidateObjectState::Prepared {
76                ownership: PendingCandidateOwnership {
77                    pending: BTreeSet::from([owner]),
78                    nonactivated: Vec::new(),
79                },
80            },
81        });
82        record.validate_payload(canonical_signed_bytes)?;
83        ClosedRemoteObject::with_spooled_payloads(record, canonical_signed_bytes, stored_bytes)
84    }
85
86    pub(super) fn candidate_activated_retained_authority(
87        domain: RetainedAuthorityObjectDomain,
88        semantic_hash: ObjectHash,
89        object: ExactObjectRef,
90        canonical_signed_bytes: &[u8],
91        stored_bytes: &[u8],
92        owner: StoreBatchCommitRef,
93    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
94        let record = Self::RetainedAuthority(RetainedAuthorityRecord {
95            identity: RetainedAuthorityObjectRef {
96                domain,
97                semantic_hash,
98                object,
99            },
100            payloads: RemoteObjectPayloads::SpooledInline,
101            state: RetainedAuthorityObjectState::Prepared {
102                ownership: PendingCandidateOwnership {
103                    pending: BTreeSet::from([owner]),
104                    nonactivated: Vec::new(),
105                },
106            },
107        });
108        record.validate_payload(canonical_signed_bytes)?;
109        ClosedRemoteObject::with_spooled_payloads(record, canonical_signed_bytes, stored_bytes)
110    }
111
112    pub fn candidate_commit(
113        identity: StoreBatchCommitRef,
114        canonical_signed_bytes: &[u8],
115        stored_bytes: &[u8],
116    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
117        let record = Self::CandidateCommit(CandidateCommitRecord {
118            identity,
119            semantic_hash: ObjectHash::digest(canonical_signed_bytes),
120            payloads: RemoteObjectPayloads::SpooledInline,
121            state: CandidateCommitState::Prepared,
122        });
123        record.validate_payload(canonical_signed_bytes)?;
124        ClosedRemoteObject::with_spooled_payloads(record, canonical_signed_bytes, stored_bytes)
125    }
126
127    pub(crate) fn candidate_activated_store_acknowledgement(
128        reference: crate::store_commit::StoreAckRef,
129        canonical_signed_bytes: &[u8],
130        stored_bytes: &[u8],
131        owner: StoreBatchCommitRef,
132    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
133        let object = reference.object.clone();
134        Self::candidate_activated_retained_authority(
135            RetainedAuthorityObjectDomain::Acknowledgement { reference },
136            ObjectHash::digest(canonical_signed_bytes),
137            object,
138            canonical_signed_bytes,
139            stored_bytes,
140            owner,
141        )
142    }
143
144    pub(crate) fn candidate_activated_circle_acknowledgement(
145        reference: CircleAckRef,
146        canonical_semantic_bytes: &[u8],
147        stored_bytes: &[u8],
148        owner: StoreBatchCommitRef,
149    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
150        let object = reference.object.clone();
151        Self::candidate_activated_retained_authority(
152            RetainedAuthorityObjectDomain::CircleAcknowledgement { reference },
153            ObjectHash::digest(canonical_semantic_bytes),
154            object,
155            canonical_semantic_bytes,
156            stored_bytes,
157            owner,
158        )
159    }
160
161    pub fn candidate_activated_provider_access_grant(
162        reference: crate::provider::StoreMemberProviderAccessGrantRef,
163        canonical_signed_bytes: &[u8],
164        stored_bytes: &[u8],
165        owner: StoreBatchCommitRef,
166    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
167        let object = reference.object.clone();
168        Self::candidate_activated_retained_authority(
169            RetainedAuthorityObjectDomain::ProviderAccessGrant { reference },
170            ObjectHash::digest(canonical_signed_bytes),
171            object,
172            canonical_signed_bytes,
173            stored_bytes,
174            owner,
175        )
176    }
177
178    pub fn candidate_activated_device_join_abandonment(
179        reference: crate::store_commit::DeviceJoinAbandonmentRef,
180        canonical_signed_bytes: &[u8],
181        stored_bytes: &[u8],
182        owner: StoreBatchCommitRef,
183    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
184        let object = reference.object.clone();
185        Self::candidate_activated_retained_authority(
186            RetainedAuthorityObjectDomain::DeviceJoinAbandonment { reference },
187            ObjectHash::digest(canonical_signed_bytes),
188            object,
189            canonical_signed_bytes,
190            stored_bytes,
191            owner,
192        )
193    }
194
195    pub fn candidate_activated_device_registration(
196        reference: crate::store_commit::StoreDeviceRegistrationRef,
197        canonical_signed_bytes: &[u8],
198        stored_bytes: &[u8],
199        owner: StoreBatchCommitRef,
200    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
201        let object = reference.object.clone();
202        Self::candidate_activated_retained_authority(
203            RetainedAuthorityObjectDomain::DeviceRegistration { reference },
204            ObjectHash::digest(canonical_signed_bytes),
205            object,
206            canonical_signed_bytes,
207            stored_bytes,
208            owner,
209        )
210    }
211
212    pub fn candidate_exclusive_merge_membership_entry(
213        family: CandidateFamilyId,
214        reference: crate::membership::MembershipEntryRef,
215        canonical_signed_bytes: &[u8],
216        stored_bytes: &[u8],
217        owner: StoreBatchCommitRef,
218    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
219        Self::candidate_exclusive_retained_authority(
220            family,
221            CandidateExclusiveObjectDomain::MergeMembershipEntry { family, reference },
222            canonical_signed_bytes,
223            stored_bytes,
224            owner,
225        )
226    }
227
228    pub fn candidate_exclusive_merge_membership_head(
229        family: CandidateFamilyId,
230        reference: crate::membership::MembershipHeadRef,
231        canonical_signed_bytes: &[u8],
232        stored_bytes: &[u8],
233        owner: StoreBatchCommitRef,
234    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
235        Self::candidate_exclusive_retained_authority(
236            family,
237            CandidateExclusiveObjectDomain::MergeMembershipHead { family, reference },
238            canonical_signed_bytes,
239            stored_bytes,
240            owner,
241        )
242    }
243
244    pub(crate) fn candidate_exclusive_merge_membership_wrapped_store_key(
245        family: CandidateFamilyId,
246        reference: crate::wrapped_store_key::WrappedStoreKeyRef,
247        canonical_signed_bytes: &[u8],
248        stored_bytes: &[u8],
249        owner: StoreBatchCommitRef,
250    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
251        Self::candidate_exclusive_retained_authority(
252            family,
253            CandidateExclusiveObjectDomain::MergeMembershipWrappedStoreKey { family, reference },
254            canonical_signed_bytes,
255            stored_bytes,
256            owner,
257        )
258    }
259
260    pub(crate) fn candidate_activated_device_exclusion_proposal(
261        reference: crate::store_commit::StoreDeviceExclusionProposalRef,
262        canonical_signed_bytes: &[u8],
263        stored_bytes: &[u8],
264        owner: StoreBatchCommitRef,
265    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
266        let object = reference.object.clone();
267        let semantic_hash = ObjectHash::digest(canonical_signed_bytes);
268        Self::candidate_activated_retained_authority(
269            RetainedAuthorityObjectDomain::DeviceExclusionProposal { reference },
270            semantic_hash,
271            object,
272            canonical_signed_bytes,
273            stored_bytes,
274            owner,
275        )
276    }
277
278    pub(crate) fn candidate_activated_device_exclusion_outcome(
279        reference: crate::store_commit::StoreDeviceExclusionOutcomeRef,
280        canonical_signed_bytes: &[u8],
281        stored_bytes: &[u8],
282        owner: StoreBatchCommitRef,
283    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
284        let object = reference.object().clone();
285        let semantic_hash = ObjectHash::digest(canonical_signed_bytes);
286        Self::candidate_activated_retained_authority(
287            RetainedAuthorityObjectDomain::DeviceExclusionOutcome { reference },
288            semantic_hash,
289            object,
290            canonical_signed_bytes,
291            stored_bytes,
292            owner,
293        )
294    }
295
296    pub fn candidate_activated_reclaim_evidence(
297        reference: crate::reclaim::ReclaimEvidenceRef,
298        canonical_signed_bytes: &[u8],
299        stored_bytes: &[u8],
300        owner: StoreBatchCommitRef,
301    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
302        let object = reference.object.clone();
303        Self::candidate_activated_retained_authority(
304            RetainedAuthorityObjectDomain::ReclaimEvidence { reference },
305            ObjectHash::digest(canonical_signed_bytes),
306            object,
307            canonical_signed_bytes,
308            stored_bytes,
309            owner,
310        )
311    }
312
313    pub fn candidate_activated_reclaim_authorization(
314        reference: crate::reclaim::ReclaimAuthorizationRef,
315        canonical_signed_bytes: &[u8],
316        stored_bytes: &[u8],
317        owner: StoreBatchCommitRef,
318    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
319        let object = reference.object.clone();
320        Self::candidate_activated_retained_authority(
321            RetainedAuthorityObjectDomain::ReclaimAuthorization { reference },
322            ObjectHash::digest(canonical_signed_bytes),
323            object,
324            canonical_signed_bytes,
325            stored_bytes,
326            owner,
327        )
328    }
329
330    pub fn candidate_activated_reclaim_receipt(
331        reference: crate::reclaim::ReclaimReceiptRef,
332        canonical_signed_bytes: &[u8],
333        stored_bytes: &[u8],
334        owner: StoreBatchCommitRef,
335    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
336        let object = reference.object.clone();
337        Self::candidate_activated_retained_authority(
338            RetainedAuthorityObjectDomain::ReclaimReceipt { reference },
339            ObjectHash::digest(canonical_signed_bytes),
340            object,
341            canonical_signed_bytes,
342            stored_bytes,
343            owner,
344        )
345    }
346
347    pub fn snapshot_activated_blob(
348        stored: &crate::blob::locator::StoredBlobRef,
349        owner: SnapshotObjectOwner,
350    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
351        let locator_bytes = stored.locator().to_bytes();
352        let record = Self::SharedLiveSet(SharedObjectRecord {
353            identity: SharedLiveSetObjectRef {
354                domain: SharedLiveSetObjectDomain::StoredBlob,
355                semantic_hash: ObjectHash::digest(&locator_bytes),
356                object: stored.object().clone(),
357            },
358            payloads: RemoteObjectPayloads::RowBlob { locator_bytes },
359            state: OwnedObjectState::UploadedVerified {
360                ownership: SharedObjectOwnership {
361                    pending: BTreeSet::new(),
362                    activated: BTreeSet::from([SharedObjectOwner::Snapshot(owner)]),
363                    nonactivated: Vec::new(),
364                },
365            },
366        });
367        ClosedRemoteObject::carried(record)
368    }
369
370    pub fn snapshot_activated_image(
371        image: &crate::store_commit::SnapshotImageRef,
372        owner: SnapshotObjectOwner,
373    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
374        let record = Self::SharedLiveSet(SharedObjectRecord {
375            identity: SharedLiveSetObjectRef {
376                domain: SharedLiveSetObjectDomain::StoreSnapshotImage {
377                    reference: image.clone(),
378                },
379                semantic_hash: image.image_hash,
380                object: image.object.clone(),
381            },
382            payloads: RemoteObjectPayloads::SpooledExternal,
383            state: OwnedObjectState::UploadedVerified {
384                ownership: SharedObjectOwnership {
385                    pending: BTreeSet::new(),
386                    activated: BTreeSet::from([SharedObjectOwner::Snapshot(owner)]),
387                    nonactivated: Vec::new(),
388                },
389            },
390        });
391        ClosedRemoteObject::carried(record)
392    }
393
394    /// The membership rollup bound to one exact snapshot metadata candidate.
395    /// Its metadata slot determines the artifact slot; another snapshot uses
396    /// another object even when its rollup bytes are identical.
397    pub fn snapshot_activated_membership_rollup(
398        rollup: &crate::store_commit::MembershipRollupRef,
399        owner: SnapshotObjectOwner,
400    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
401        let record = Self::SharedLiveSet(SharedObjectRecord {
402            identity: SharedLiveSetObjectRef {
403                domain: SharedLiveSetObjectDomain::StoreMembershipRollup {
404                    reference: rollup.clone(),
405                },
406                semantic_hash: rollup.rollup_hash,
407                object: rollup.object.clone(),
408            },
409            payloads: RemoteObjectPayloads::SpooledExternal,
410            state: OwnedObjectState::UploadedVerified {
411                ownership: SharedObjectOwnership {
412                    pending: BTreeSet::new(),
413                    activated: BTreeSet::from([SharedObjectOwner::Snapshot(owner)]),
414                    nonactivated: Vec::new(),
415                },
416            },
417        });
418        ClosedRemoteObject::carried(record)
419    }
420
421    pub fn activated_external_package(
422        domain: SharedLiveSetObjectDomain,
423        package: &crate::audience_package::AudiencePackage,
424        owner: StoreBatchCommitRef,
425    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
426        if !matches!(
427            domain,
428            SharedLiveSetObjectDomain::StorePackage { .. }
429                | SharedLiveSetObjectDomain::CirclePackage { .. }
430        ) {
431            return Err(RemoteObjectRecordError::DomainMismatch);
432        }
433        let canonical_semantic_bytes = package.to_bytes();
434        let object = domain.package_object()?.clone();
435        let record = Self::SharedLiveSet(SharedObjectRecord {
436            identity: SharedLiveSetObjectRef {
437                domain,
438                semantic_hash: ObjectHash::digest(&canonical_semantic_bytes),
439                object,
440            },
441            payloads: RemoteObjectPayloads::SpooledExternal,
442            state: OwnedObjectState::UploadedVerified {
443                ownership: SharedObjectOwnership {
444                    pending: BTreeSet::new(),
445                    activated: BTreeSet::from([SharedObjectOwner::StoreCommit(owner)]),
446                    nonactivated: Vec::new(),
447                },
448            },
449        });
450        record.validate_payload(&canonical_semantic_bytes)?;
451        let hash = ObjectHash::digest(&canonical_semantic_bytes);
452        ClosedRemoteObject::with_payloads(
453            record,
454            BTreeMap::from([(hash, canonical_semantic_bytes)]),
455        )
456    }
457
458    pub fn activated_blob(
459        stored: &crate::blob::locator::StoredBlobRef,
460        owner: StoreBatchCommitRef,
461    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
462        let locator_bytes = stored.locator().to_bytes();
463        let record = Self::SharedLiveSet(SharedObjectRecord {
464            identity: SharedLiveSetObjectRef {
465                domain: SharedLiveSetObjectDomain::StoredBlob,
466                semantic_hash: ObjectHash::digest(&locator_bytes),
467                object: stored.object().clone(),
468            },
469            payloads: RemoteObjectPayloads::RowBlob { locator_bytes },
470            state: OwnedObjectState::UploadedVerified {
471                ownership: SharedObjectOwnership {
472                    pending: BTreeSet::new(),
473                    activated: BTreeSet::from([SharedObjectOwner::StoreCommit(owner)]),
474                    nonactivated: Vec::new(),
475                },
476            },
477        });
478        ClosedRemoteObject::carried(record)
479    }
480
481    pub fn candidate_owned_blob(
482        stored: &crate::blob::locator::StoredBlobRef,
483        owner: StoreBatchCommitRef,
484        uploaded_verified: bool,
485    ) -> Result<ClosedRemoteObject, RemoteObjectRecordError> {
486        let locator_bytes = stored.locator().to_bytes();
487        let ownership = PendingCandidateOwnership {
488            pending: BTreeSet::from([owner]),
489            nonactivated: Vec::new(),
490        };
491        let state = if uploaded_verified {
492            OwnedObjectState::UploadedVerified {
493                ownership: SharedObjectOwnership {
494                    pending: ownership.pending,
495                    activated: BTreeSet::new(),
496                    nonactivated: ownership.nonactivated,
497                },
498            }
499        } else {
500            OwnedObjectState::Prepared { ownership }
501        };
502        let record = Self::SharedLiveSet(SharedObjectRecord {
503            identity: SharedLiveSetObjectRef {
504                domain: SharedLiveSetObjectDomain::StoredBlob,
505                semantic_hash: ObjectHash::digest(&locator_bytes),
506                object: stored.object().clone(),
507            },
508            payloads: RemoteObjectPayloads::RowBlob { locator_bytes },
509            state,
510        });
511        ClosedRemoteObject::carried(record)
512    }
513}