Skip to main content

lsp_max/runtime/control_plane/kernel/
refused_quarantined_replayed.rs

1use crate::runtime::control_plane::admission::{
2    CandidateData, GraphAdmissionError, GraphAdmissionLaw, QuarantinedData, RefusedData,
3    ReplayedData, CANDIDATE, QUARANTINED, REFUSED, REPLAYED,
4};
5use crate::runtime::control_plane::receipts::{Blake3Hash, CryptographicReceipt};
6use crate::runtime::{ChainError, Machine, TypestateKernel};
7use ed25519_dalek::Signer;
8
9// ==========================================
10// TypestateKernel for REFUSED
11// ==========================================
12impl TypestateKernel<GraphAdmissionLaw, REFUSED, RefusedData>
13    for Machine<GraphAdmissionLaw, REFUSED, RefusedData>
14{
15    type Input = ();
16    type OutputPhase = REFUSED;
17    type OutputData = RefusedData;
18    type Receipt = CryptographicReceipt;
19
20    fn validate(&self, _input: &Self::Input) -> Result<(), GraphAdmissionError> {
21        Err(GraphAdmissionError::ParsingFailed(
22            "Already refused".to_string(),
23        ))
24    }
25
26    fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
27        REFUSED
28    }
29
30    fn admit(
31        self,
32        input: Self::Input,
33    ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
34    {
35        self.validate(&input)?;
36        Ok(self)
37    }
38
39    fn receipt(&self) -> Self::Receipt {
40        let mut receipt = CryptographicReceipt {
41            prev_hash: Blake3Hash([0u8; 32]),
42            discipline_id: uuid::Uuid::nil(),
43            law_id: uuid::Uuid::nil(),
44            consequence_hash: Blake3Hash([0u8; 32]),
45            sequence: 2,
46            signature: [0u8; 64],
47        };
48        let payload_hash = receipt.compute_payload_hash();
49        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
50        receipt.signature = signing_key.sign(&payload_hash.0).to_bytes();
51        receipt
52    }
53
54    fn exit(self) -> RefusedData {
55        self.data
56    }
57
58    fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
59        if history.len() < 3 {
60            return Err(ChainError::InsufficientHistory {
61                required: 3,
62                got: history.len(),
63            });
64        }
65        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
66        let verifying_key = signing_key.verifying_key();
67        crate::runtime::control_plane::receipts::verify_receipt_chain(
68            &history,
69            &verifying_key,
70            &history[0].prev_hash,
71        )
72        .map_err(|e| ChainError::HashMismatch {
73            index: 2,
74            expected: "Valid signature".to_string(),
75            got: e.to_string(),
76        })?;
77
78        Ok(Machine::new(
79            REFUSED,
80            RefusedData {
81                report: crate::runtime::control_plane::invariants::VerificationReport {
82                    is_success: false,
83                    diagnostics: Vec::new(),
84                    execution_time_ms: 0,
85                },
86            },
87        ))
88    }
89}
90
91// ==========================================
92// TypestateKernel for QUARANTINED
93// ==========================================
94impl TypestateKernel<GraphAdmissionLaw, QUARANTINED, QuarantinedData>
95    for Machine<GraphAdmissionLaw, QUARANTINED, QuarantinedData>
96{
97    type Input = String; // representing graph_hash
98    type OutputPhase = CANDIDATE;
99    type OutputData = CandidateData;
100    type Receipt = CryptographicReceipt;
101
102    fn validate(&self, _input: &Self::Input) -> Result<(), GraphAdmissionError> {
103        Ok(())
104    }
105
106    fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
107        CANDIDATE
108    }
109
110    fn admit(
111        self,
112        input: Self::Input,
113    ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
114    {
115        self.validate(&input)?;
116        Ok(self.into_candidate(input))
117    }
118
119    fn receipt(&self) -> Self::Receipt {
120        let mut receipt = CryptographicReceipt {
121            prev_hash: Blake3Hash([0u8; 32]),
122            discipline_id: uuid::Uuid::nil(),
123            law_id: uuid::Uuid::nil(),
124            consequence_hash: Blake3Hash([0u8; 32]),
125            sequence: 2,
126            signature: [0u8; 64],
127        };
128        let payload_hash = receipt.compute_payload_hash();
129        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
130        receipt.signature = signing_key.sign(&payload_hash.0).to_bytes();
131        receipt
132    }
133
134    fn exit(self) -> QuarantinedData {
135        self.data
136    }
137
138    fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
139        if history.len() < 3 {
140            return Err(ChainError::InsufficientHistory {
141                required: 3,
142                got: history.len(),
143            });
144        }
145        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
146        let verifying_key = signing_key.verifying_key();
147        crate::runtime::control_plane::receipts::verify_receipt_chain(
148            &history,
149            &verifying_key,
150            &history[0].prev_hash,
151        )
152        .map_err(|e| ChainError::HashMismatch {
153            index: 2,
154            expected: "Valid signature".to_string(),
155            got: e.to_string(),
156        })?;
157
158        Ok(Machine::new(
159            QUARANTINED,
160            QuarantinedData {
161                elements: Vec::new(),
162                quads: Vec::new(),
163                missing_dependencies: Vec::new(),
164            },
165        ))
166    }
167}
168
169// ==========================================
170// TypestateKernel for REPLAYED
171// ==========================================
172impl TypestateKernel<GraphAdmissionLaw, REPLAYED, ReplayedData>
173    for Machine<GraphAdmissionLaw, REPLAYED, ReplayedData>
174{
175    type Input = ();
176    type OutputPhase = REPLAYED;
177    type OutputData = ReplayedData;
178    type Receipt = CryptographicReceipt;
179
180    fn validate(&self, _input: &Self::Input) -> Result<(), GraphAdmissionError> {
181        Err(GraphAdmissionError::ParsingFailed(
182            "Already replayed".to_string(),
183        ))
184    }
185
186    fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
187        REPLAYED
188    }
189
190    fn admit(
191        self,
192        input: Self::Input,
193    ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
194    {
195        self.validate(&input)?;
196        Ok(self)
197    }
198
199    fn receipt(&self) -> Self::Receipt {
200        self.data.receipt.clone()
201    }
202
203    fn exit(self) -> ReplayedData {
204        self.data
205    }
206
207    fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
208        if history.len() < 3 {
209            return Err(ChainError::InsufficientHistory {
210                required: 3,
211                got: history.len(),
212            });
213        }
214        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
215        let verifying_key = signing_key.verifying_key();
216        crate::runtime::control_plane::receipts::verify_receipt_chain(
217            &history,
218            &verifying_key,
219            &history[0].prev_hash,
220        )
221        .map_err(|e| ChainError::HashMismatch {
222            index: 2,
223            expected: "Valid signature".to_string(),
224            got: e.to_string(),
225        })?;
226
227        Ok(Machine::new(
228            REPLAYED,
229            ReplayedData {
230                graph_name: oxigraph::model::GraphName::DefaultGraph,
231                receipt: history[2].clone(),
232            },
233        ))
234    }
235}