1use crate::{
2 CertificateLimits, ProgramArtifact, ProgramUpdateMode, RipsParams, SparseDistanceMatrix,
3};
4
5use super::codec::{Reader, program_artifact_error};
6use super::envelope::{
7 STEP_MINIMUM_BYTES, check_count_bytes, check_envelope_size, check_no_trailing_bytes,
8 decode_program_artifact, decode_trace_header, decode_trace_steps, encode_checkpoints,
9 encode_program_artifact, encode_trace_header, encode_trace_step,
10};
11use super::model::{
12 ProgramTraceArtifact, ProgramTraceDecodeLimits, ProgramTraceError, ProgramTraceStep,
13 TraceTotals, VerifiedProgramTrace,
14};
15use super::records::{decode_graph, encode_graph};
16use super::replay::{check_replayed_step, check_step_shape, replay_step, verify_program_artifact};
17
18impl ProgramTraceArtifact {
19 pub fn build(
21 initial: &SparseDistanceMatrix,
22 updates: &[SparseDistanceMatrix],
23 params: &RipsParams,
24 certificate_limits: CertificateLimits,
25 ) -> std::result::Result<Self, ProgramTraceError> {
26 let (initial_program, mut program) =
27 ProgramArtifact::compile(initial, params, certificate_limits)
28 .map_err(program_artifact_error)?;
29 let mut steps = Vec::with_capacity(updates.len());
30 for graph in updates {
31 let update = program
32 .advance(graph)
33 .map_err(|error| ProgramTraceError::new(error.to_string()))?;
34 let checkpoint = (update.mode != ProgramUpdateMode::Reused)
35 .then(|| ProgramArtifact::capture(graph, &program))
36 .transpose()
37 .map_err(program_artifact_error)?;
38 steps.push(ProgramTraceStep {
39 graph: graph.clone(),
40 mode: update.mode,
41 work: update.work,
42 events: update.events,
43 continuation: update.continuation,
44 correspondence: update.correspondence,
45 diagram: update.result.diagram,
46 checkpoint,
47 });
48 }
49 Ok(Self {
50 initial_graph: initial.clone(),
51 initial_program,
52 steps,
53 })
54 }
55
56 pub fn initial_graph(&self) -> &SparseDistanceMatrix {
58 &self.initial_graph
59 }
60
61 pub fn initial_program(&self) -> &ProgramArtifact {
63 &self.initial_program
64 }
65
66 pub fn steps(&self) -> &[ProgramTraceStep] {
68 &self.steps
69 }
70
71 pub fn encode(&self) -> std::result::Result<Vec<u8>, ProgramTraceError> {
73 let initial_program = encode_program_artifact(&self.initial_program)?;
74 let checkpoints = encode_checkpoints(&self.steps)?;
75 let mut out = Vec::new();
76 encode_trace_header(&mut out, self.steps.len(), initial_program.len())?;
77 encode_graph(&mut out, &self.initial_graph)?;
78 out.extend_from_slice(&initial_program);
79 for (step, checkpoint) in self.steps.iter().zip(checkpoints) {
80 encode_trace_step(&mut out, step, checkpoint.as_deref())?;
81 }
82 Ok(out)
83 }
84
85 pub fn decode(
87 bytes: &[u8],
88 limits: ProgramTraceDecodeLimits,
89 certificate_limits: CertificateLimits,
90 ) -> std::result::Result<Self, ProgramTraceError> {
91 check_envelope_size(bytes, limits.max_bytes)?;
92 let mut reader = Reader::new(bytes);
93 let header = decode_trace_header(&mut reader, limits)?;
94 let mut total_edges = 0usize;
95 let initial_graph = decode_graph(&mut reader, limits, &mut total_edges)?;
96 let initial_program = decode_program_artifact(
97 &mut reader,
98 header.initial_program_bytes,
99 limits,
100 certificate_limits,
101 )?;
102 let mut totals = TraceTotals {
103 checkpoint_bytes: header.initial_program_bytes,
104 ..TraceTotals::default()
105 };
106 check_count_bytes(
107 &reader,
108 header.step_count,
109 STEP_MINIMUM_BYTES,
110 "trace step records",
111 )?;
112 let steps = decode_trace_steps(
113 &mut reader,
114 header.step_count,
115 limits,
116 certificate_limits,
117 initial_program.modulus(),
118 &mut totals,
119 &mut total_edges,
120 )?;
121 check_no_trailing_bytes(&reader)?;
122 Ok(Self {
123 initial_graph,
124 initial_program,
125 steps,
126 })
127 }
128
129 pub fn verify(
131 &self,
132 certificate_limits: CertificateLimits,
133 ) -> std::result::Result<VerifiedProgramTrace, ProgramTraceError> {
134 let mut program = verify_program_artifact(
135 &self.initial_program,
136 &self.initial_graph,
137 certificate_limits,
138 )?;
139 let initial_result = program.result().clone();
140 let mut verified_steps = Vec::with_capacity(self.steps.len());
141 for (index, step) in self.steps.iter().enumerate() {
142 check_step_shape(step)?;
143 let checked = replay_step(&mut program, step, index, certificate_limits)?;
144 check_replayed_step(&checked, step, index)?;
145 verified_steps.push(checked.into());
146 }
147 Ok(VerifiedProgramTrace {
148 initial_result,
149 steps: verified_steps,
150 final_program: program,
151 })
152 }
153}