coven_database/store/
device_join_bootstrap.rs1use 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}