1use super::status::{AuthorityMaterial, archived_authorities};
4use super::{ArchiveError, Archived, ArtifactRef, Coverage, Index, IndexError};
5use crate::pki::{Participant, ParticipantAuthority, ParticipantClosure};
6use crate::source::Query;
7use crate::timestamp::{Purpose, TimestampScope, Verified};
8use structured_asn1::memory::{HashWork, MemoryError, OwnedVec, Work};
9
10pub struct AnchorMaterial<N, D, G, P> {
12 participant: Participant<N>,
13 certificate: Option<Archived<N, D, G, P>>,
14}
15
16impl<N: Copy, D, G, P> AnchorMaterial<N, D, G, P> {
17 #[must_use]
19 pub fn participant(&self) -> Participant<N> {
20 self.participant
21 }
22
23 #[must_use]
26 pub fn certificate(&self) -> Option<&Archived<N, D, G, P>> {
27 self.certificate.as_ref()
28 }
29}
30
31pub struct ParticipantMaterial<
36 'closure,
37 'requirements,
38 'view,
39 'certificate,
40 'document,
41 N,
42 D,
43 G,
44 P,
45 I,
46> {
47 inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
48 authorities: AuthorityMaterial<'closure, 'view, 'certificate, 'document, N, D, G, P>,
49 anchors: OwnedVec<AnchorMaterial<N, D, G, P>>,
50 all_covered: bool,
51}
52
53impl<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, P, I>
54 ParticipantMaterial<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, P, I>
55{
56 #[must_use]
58 pub fn inputs(
59 &self,
60 ) -> &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>
61 {
62 self.inputs
63 }
64
65 #[must_use]
67 pub fn authorities(
68 &self,
69 ) -> &AuthorityMaterial<'closure, 'view, 'certificate, 'document, N, D, G, P> {
70 &self.authorities
71 }
72
73 #[must_use]
75 pub fn anchors(&self) -> &[AnchorMaterial<N, D, G, P>] {
76 &self.anchors
77 }
78
79 #[must_use]
82 pub fn all_x509_artifacts_covered(&self) -> bool {
83 self.all_covered
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum ParticipantArchiveError<N> {
90 Foreign {
92 expected: N,
94 actual: N,
96 },
97 Material(ArchiveError<N>),
99 Resource {
101 archive: N,
103 cause: MemoryError,
105 },
106}
107
108pub fn archived_participants<
118 'closure,
119 'requirements,
120 'view,
121 'certificate,
122 'document,
123 N,
124 D,
125 G,
126 P,
127 O,
128 W,
129 Q,
130 C,
131 I,
132>(
133 inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
134 index: &Index<'_, N, D, G, P, O, W, I>,
135 coverage: &Coverage<N, D, G, C, I>,
136 evidence: &Verified<N, D, G, I>,
137 query: &Q,
138) -> Result<
139 ParticipantMaterial<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, P, I>,
140 ParticipantArchiveError<N>,
141>
142where
143 N: Copy + Eq + HashWork,
144 D: Copy + Eq,
145 G: Copy + Eq,
146 P: Copy,
147 W: Work,
148 C: Work,
149 Q: Query<Id = N, Document = D, Generation = G>,
150{
151 let required = inputs.requirements();
152 let scope = required.scope();
153 let archive = scope.location();
154 let foreign = || ParticipantArchiveError::Foreign {
155 expected: archive.node,
156 actual: evidence.property(),
157 };
158 if !matches!(scope, TimestampScope::BeforeArchive(_))
159 || archive.snapshot != query.snapshot()
160 || archive.snapshot != evidence.token().snapshot
161 {
162 return Err(foreign());
163 }
164 let resource = |cause| ParticipantArchiveError::Resource {
165 archive: archive.node,
166 cause,
167 };
168 query.admit(archive.node, 1).map_err(|cause| {
169 ParticipantArchiveError::Material(ArchiveError::Index(IndexError::Scope(cause)))
170 })?;
171 let mut anchors = query.execution().vector();
172 let cost = archive
173 .node
174 .hash_work()
175 .and_then(|cost| {
176 cost.checked_add(evidence.property().hash_work()?)
177 .ok_or(MemoryError::WorkExceeded)
178 })
179 .and_then(|cost| {
180 cost.checked_add(required.signature().hash_work()?)
181 .ok_or(MemoryError::WorkExceeded)
182 })
183 .and_then(|cost| {
184 cost.checked_add(evidence.signature().hash_work()?)
185 .ok_or(MemoryError::WorkExceeded)
186 })
187 .map_err(resource)?;
188 query.execution().charge_work(cost).map_err(resource)?;
189 if archive.node != evidence.property()
190 || required.signature() != evidence.signature()
191 || evidence.purpose() != Purpose::Archive
192 {
193 return Err(foreign());
194 }
195 coverage
196 .require_evidence(evidence, archive.node, query)
197 .map_err(|cause| ParticipantArchiveError::Material(ArchiveError::Coverage(cause)))?;
198 let authorities = archived_authorities(inputs.authorities(), index, coverage, evidence, query)
199 .map_err(ParticipantArchiveError::Material)?;
200 let mut all_covered = authorities.all_artifacts_covered();
201 for entry in required.entries() {
202 query.execution().charge_work(1).map_err(resource)?;
203 let ParticipantAuthority::Anchor(anchor) = entry.authority() else {
204 continue;
205 };
206 let certificate = match anchor.anchor().certificate() {
207 Some(certificate) => {
208 let value = index
209 .archived(
210 ArtifactRef::Certificate(certificate),
211 coverage,
212 evidence,
213 query,
214 )
215 .map_err(ParticipantArchiveError::Material)?;
216 if !matches!(value, Archived::Present(_)) {
217 all_covered = false;
218 }
219 Some(value)
220 }
221 None => None,
222 };
223 anchors
224 .try_push(AnchorMaterial {
225 participant: entry.participant(),
226 certificate,
227 })
228 .map_err(resource)?;
229 }
230 Ok(ParticipantMaterial {
231 inputs,
232 authorities,
233 anchors: anchors.into_owned(),
234 all_covered,
235 })
236}