Skip to main content

lsp_max/runtime/control_plane/kernel/
admitted_superseded.rs

1use crate::runtime::control_plane::admission::{
2    AdmittedData, GraphAdmissionError, GraphAdmissionLaw, SupersededData, ADMITTED, SUPERSEDED,
3};
4use crate::runtime::control_plane::receipts::{Blake3Hash, CryptographicReceipt};
5use crate::runtime::{ChainError, Machine, TypestateKernel};
6use ed25519_dalek::Signer;
7
8// ==========================================
9// TypestateKernel for ADMITTED
10// ==========================================
11impl TypestateKernel<GraphAdmissionLaw, ADMITTED, AdmittedData>
12    for Machine<GraphAdmissionLaw, ADMITTED, AdmittedData>
13{
14    type Input = oxigraph::model::GraphName;
15    type OutputPhase = SUPERSEDED;
16    type OutputData = SupersededData;
17    type Receipt = CryptographicReceipt;
18
19    fn validate(&self, _input: &Self::Input) -> Result<(), GraphAdmissionError> {
20        Ok(())
21    }
22
23    fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
24        SUPERSEDED
25    }
26
27    fn admit(
28        self,
29        input: Self::Input,
30    ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
31    {
32        self.validate(&input)?;
33        Ok(self.admit_supersede(input))
34    }
35
36    fn receipt(&self) -> Self::Receipt {
37        self.data.receipt.clone()
38    }
39
40    fn exit(self) -> AdmittedData {
41        self.data
42    }
43
44    fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
45        if history.len() < 3 {
46            return Err(ChainError::InsufficientHistory {
47                required: 3,
48                got: history.len(),
49            });
50        }
51        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
52        let verifying_key = signing_key.verifying_key();
53        crate::runtime::control_plane::receipts::verify_receipt_chain(
54            &history,
55            &verifying_key,
56            &history[0].prev_hash,
57        )
58        .map_err(|e| ChainError::HashMismatch {
59            index: 2,
60            expected: "Valid signature".to_string(),
61            got: e.to_string(),
62        })?;
63
64        Ok(Machine::new(
65            ADMITTED,
66            AdmittedData {
67                graph_name: oxigraph::model::GraphName::DefaultGraph,
68                quad_count: 0,
69                receipt: history[2].clone(),
70            },
71        ))
72    }
73}
74
75// ==========================================
76// TypestateKernel for SUPERSEDED
77// ==========================================
78impl TypestateKernel<GraphAdmissionLaw, SUPERSEDED, SupersededData>
79    for Machine<GraphAdmissionLaw, SUPERSEDED, SupersededData>
80{
81    type Input = ();
82    type OutputPhase = SUPERSEDED;
83    type OutputData = SupersededData;
84    type Receipt = CryptographicReceipt;
85
86    fn validate(&self, _input: &Self::Input) -> Result<(), GraphAdmissionError> {
87        Err(GraphAdmissionError::ParsingFailed(
88            "Already superseded".to_string(),
89        ))
90    }
91
92    fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
93        SUPERSEDED
94    }
95
96    fn admit(
97        self,
98        input: Self::Input,
99    ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
100    {
101        self.validate(&input)?;
102        Ok(self)
103    }
104
105    fn receipt(&self) -> Self::Receipt {
106        let mut receipt = CryptographicReceipt {
107            prev_hash: Blake3Hash([0u8; 32]),
108            discipline_id: uuid::Uuid::nil(),
109            law_id: uuid::Uuid::nil(),
110            consequence_hash: Blake3Hash([0u8; 32]),
111            sequence: 3,
112            signature: [0u8; 64],
113        };
114        let payload_hash = receipt.compute_payload_hash();
115        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
116        receipt.signature = signing_key.sign(&payload_hash.0).to_bytes();
117        receipt
118    }
119
120    fn exit(self) -> SupersededData {
121        self.data
122    }
123
124    fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
125        if history.len() < 4 {
126            return Err(ChainError::InsufficientHistory {
127                required: 4,
128                got: history.len(),
129            });
130        }
131        let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
132        let verifying_key = signing_key.verifying_key();
133        crate::runtime::control_plane::receipts::verify_receipt_chain(
134            &history,
135            &verifying_key,
136            &history[0].prev_hash,
137        )
138        .map_err(|e| ChainError::HashMismatch {
139            index: 3,
140            expected: "Valid signature".to_string(),
141            got: e.to_string(),
142        })?;
143
144        Ok(Machine::new(
145            SUPERSEDED,
146            SupersededData {
147                graph_name: oxigraph::model::GraphName::DefaultGraph,
148                superseded_by: oxigraph::model::GraphName::DefaultGraph,
149            },
150        ))
151    }
152}