Skip to main content

coven_database/store/
device_join_bootstrap.rs

1use super::*;
2
3impl DeviceJoinBootstrapPlan {
4    pub fn from_verified_commits(
5        founder: coven_protocol::store_commit::ReferencedStoreDeviceRegistration,
6        genesis: ResolvedStoreDeviceState,
7        membership: InitialStoreMembershipAuthority,
8        installed: &coven_protocol::store_commit::CommitFrontier,
9        publication: AcceptedStorePublicationInterval,
10        mut commits: std::collections::BTreeMap<StoreBatchCommitRef, DeviceJoinBootstrapCommit>,
11    ) -> Result<Self, DbError> {
12        let mut ordered = Vec::new();
13        let mut emitted = std::collections::BTreeSet::new();
14        for entry in publication.interval().entries() {
15            let coven_protocol::store_commit::StorePublicationPayload::Commit(reference) =
16                &entry.entry().payload
17            else {
18                continue;
19            };
20            let carried = commits.remove(reference).ok_or_else(|| {
21                DbError::Message(format!(
22                    "device join history omits accepted commit {reference:?}"
23                ))
24            })?;
25            if carried.reference != *reference || carried.commit.reference() != reference {
26                return Err(DbError::Message(
27                    "device join history contains another exact commit".into(),
28                ));
29            }
30            if carried
31                .commit
32                .order
33                .predecessor
34                .iter()
35                .chain(carried.commit.order.dependencies.values())
36                .any(|dependency| {
37                    !installed.covers_commit(dependency) && !emitted.contains(dependency)
38                })
39            {
40                return Err(DbError::Message(
41                    "device join publication precedes a required history input".into(),
42                ));
43            }
44            publication.accepted_commit(&carried.commit)?;
45            emitted.insert(reference.clone());
46            ordered.push(carried);
47        }
48        Ok(Self {
49            founder_reference: founder.reference().clone(),
50            founder: founder.value().clone(),
51            founder_bytes: founder.value().to_bytes(),
52            genesis,
53            membership,
54            publication,
55            commits: ordered,
56        })
57    }
58
59    pub fn verified_commit(
60        &self,
61        reference: &StoreBatchCommitRef,
62    ) -> Option<&VerifiedStoreBatchCommit> {
63        self.commits
64            .iter()
65            .find(|commit| &commit.reference == reference)
66            .map(|commit| &commit.commit)
67    }
68
69    pub fn into_closure(
70        self,
71        root: &StoreRootRef,
72    ) -> Result<
73        coven_protocol::store_commit::device_join_exchange::DeviceJoinBootstrapClosure,
74        DbError,
75    > {
76        if self.founder.store_root != *root || self.founder.to_bytes() != self.founder_bytes {
77            return Err(DbError::Message(
78                "device join bootstrap founder differs from its canonical bytes".to_string(),
79            ));
80        }
81        let founder = coven_protocol::store_commit::ReferencedStoreDeviceRegistration::verified(
82            self.founder_reference,
83            self.founder,
84        )
85        .map_err(DbError::from)?;
86        let publication = coven_protocol::store_commit::device_join_exchange::DeviceJoinBootstrapPublicationInterval {
87            previous: self.publication.interval().previous().clone(),
88            current: self.publication.interval().current().clone(),
89            entries: self
90                .publication
91                .interval()
92                .entries()
93                .iter()
94                .map(|accepted| {
95                    Ok(coven_protocol::store_commit::device_join_exchange::DeviceJoinBootstrapPublicationEntry {
96                        entry: PreparedExactObject::new(
97                            accepted.reference().object.clone(),
98                            accepted.entry().to_bytes(),
99                        )
100                        .map_err(DbError::from)?,
101                        author: accepted.author().clone(),
102                    })
103                })
104                .collect::<Result<Vec<_>, DbError>>()?,
105        };
106        let commits = self
107            .commits
108            .into_iter()
109            .map(|commit| {
110                let value = commit.commit.value();
111                if commit.commit.reference() != &commit.reference
112                    || commit.commit.store_root_hash() != root.store_root_hash
113                {
114                    return Err(DbError::Message(
115                        "device join bootstrap commit differs from its exact reference"
116                            .to_string(),
117                    ));
118                }
119                let author =
120                    coven_protocol::store_commit::ReferencedStoreDeviceRegistration::verified(
121                        value.author_registration.clone(),
122                        commit.commit.author().clone(),
123                    )
124                    .map_err(DbError::from)?;
125                let registrations = RetainedStoreDeviceRegistrationActivations::from_verified(
126                    root,
127                    value,
128                    &commit.registrations,
129                )
130                .map_err(DbError::from)?;
131                Ok(coven_protocol::store_commit::device_join_exchange::DeviceJoinBootstrapCommitClosure {
132                    reference: commit.reference,
133                    canonical_commit: value.to_bytes(),
134                    author,
135                    registrations,
136                    device_operations: commit.device_operations.to_retained(),
137                    history_evidence: commit.history_evidence,
138                })
139            })
140            .collect::<Result<Vec<_>, DbError>>()?;
141        Ok(
142            coven_protocol::store_commit::device_join_exchange::DeviceJoinBootstrapClosure {
143                founder,
144                genesis: self.genesis,
145                membership: coven_protocol::membership::MembershipFloor(self.membership.head_refs),
146                publication,
147                commits,
148            },
149        )
150    }
151
152    pub fn from_closure(
153        root: &StoreRootRef,
154        previous: coven_protocol::store_commit::StoreCurrentPublicationRecord,
155        closure: coven_protocol::store_commit::device_join_exchange::DeviceJoinBootstrapClosure,
156    ) -> Result<Self, DbError> {
157        if *previous != closure.publication.previous {
158            return Err(DbError::Message(
159                "device join history starts from another snapshot boundary".into(),
160            ));
161        }
162        let founder_reference = closure.founder.reference().clone();
163        let founder = closure.founder.value().clone();
164        let founder_bytes = founder.to_bytes();
165        if founder.store_root != *root {
166            return Err(DbError::Message(
167                "device join bootstrap founder belongs to another Store".to_string(),
168            ));
169        }
170        founder_reference
171            .object
172            .verify(&founder_bytes)
173            .map_err(DbError::from)?;
174
175        let publication = closure.publication.verify().map_err(DbError::from)?;
176        let publication = AcceptedStorePublicationInterval::from_verified(publication, None);
177
178        let commits = closure
179            .commits
180            .into_iter()
181            .map(|carried| {
182                let commit = VerifiedStoreBatchCommit::parse(
183                    &carried.canonical_commit,
184                    root.store_root_hash,
185                    &carried.reference,
186                    carried.author.value(),
187                )
188                .map_err(DbError::from)?;
189                if commit.author_registration != *carried.author.reference() {
190                    return Err(DbError::Message(
191                        "device join bootstrap commit differs from its carried author".to_string(),
192                    ));
193                }
194                publication
195                    .accepted_commit(&commit)
196                    .map_err(|error| DbError::context("device join accepted publication", error))?;
197                let registrations = carried
198                    .registrations
199                    .verify_for(root, commit.value())
200                    .map_err(DbError::from)?;
201                let device_operations = carried
202                    .device_operations
203                    .verify_for(root, commit.value())
204                    .map_err(DbError::from)?;
205                Ok(DeviceJoinBootstrapCommit {
206                    reference: carried.reference,
207                    commit,
208                    registrations,
209                    device_operations,
210                    history_evidence: carried.history_evidence,
211                })
212            })
213            .collect::<Result<Vec<_>, DbError>>()?;
214
215        Ok(Self {
216            founder_reference,
217            founder,
218            founder_bytes,
219            genesis: closure.genesis,
220            membership: InitialStoreMembershipAuthority {
221                head_refs: closure.membership.0,
222            },
223            publication,
224            commits,
225        })
226    }
227}