lsp_max/runtime/control_plane/kernel/
raw_candidate.rs1use crate::runtime::control_plane::admission::{
2 CandidateData, GraphAdmissionError, GraphAdmissionLaw, RawData, CANDIDATE, RAW,
3};
4use crate::runtime::control_plane::receipts::{Blake3Hash, CryptographicReceipt};
5use crate::runtime::{ChainError, Machine, TypestateKernel};
6use ed25519_dalek::Signer;
7
8use super::bytes_to_hex;
9use super::CandidateAdmitInput;
10
11impl TypestateKernel<GraphAdmissionLaw, RAW, RawData> for Machine<GraphAdmissionLaw, RAW, RawData> {
15 type Input = String; type OutputPhase = CANDIDATE;
17 type OutputData = CandidateData;
18 type Receipt = CryptographicReceipt;
19
20 fn validate(&self, _input: &Self::Input) -> Result<(), GraphAdmissionError> {
21 Ok(())
22 }
23
24 fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
25 CANDIDATE
26 }
27
28 fn admit(
29 self,
30 input: Self::Input,
31 ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
32 {
33 self.validate(&input)?;
34 self.admit_candidate(&input)
35 }
36
37 fn receipt(&self) -> Self::Receipt {
38 let consequence_hash = Blake3Hash([0u8; 32]);
39 let mut receipt = CryptographicReceipt {
40 prev_hash: Blake3Hash([0u8; 32]),
41 discipline_id: uuid::Uuid::nil(),
42 law_id: uuid::Uuid::nil(),
43 consequence_hash,
44 sequence: 0,
45 signature: [0u8; 64],
46 };
47 let payload_hash = receipt.compute_payload_hash();
48 let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
49 receipt.signature = signing_key.sign(&payload_hash.0).to_bytes();
50 receipt
51 }
52
53 fn exit(self) -> RawData {
54 self.data
55 }
56
57 fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
58 if history.is_empty() {
59 return Err(ChainError::EmptyHistory);
60 }
61 if history[0].sequence != 0 {
62 return Err(ChainError::ReceiptIdMismatch {
63 index: 0,
64 detail: "Expected genesis receipt with sequence 0".to_string(),
65 });
66 }
67 Ok(Machine::new(
68 RAW,
69 RawData {
70 elements: Vec::new(),
71 },
72 ))
73 }
74}
75
76impl TypestateKernel<GraphAdmissionLaw, CANDIDATE, CandidateData>
80 for Machine<GraphAdmissionLaw, CANDIDATE, CandidateData>
81{
82 type Input = CandidateAdmitInput;
83 type OutputPhase = crate::runtime::control_plane::admission::ADMITTED;
84 type OutputData = crate::runtime::control_plane::admission::AdmittedData;
85 type Receipt = CryptographicReceipt;
86
87 fn validate(&self, input: &Self::Input) -> Result<(), GraphAdmissionError> {
88 if input.receipt.sequence == 0 {
89 return Err(GraphAdmissionError::ParsingFailed(
90 "Receipt sequence cannot be 0".to_string(),
91 ));
92 }
93 Ok(())
94 }
95
96 fn select(&self, _input: &Self::Input) -> Self::OutputPhase {
97 crate::runtime::control_plane::admission::ADMITTED
98 }
99
100 fn admit(
101 self,
102 input: Self::Input,
103 ) -> Result<Machine<GraphAdmissionLaw, Self::OutputPhase, Self::OutputData>, GraphAdmissionError>
104 {
105 self.validate(&input)?;
106 self.admit_admitted(&input.store, input.graph_name, input.receipt)
107 }
108
109 fn receipt(&self) -> Self::Receipt {
110 let mut hasher = blake3::Hasher::new();
111 hasher.update(self.data.graph_hash.as_bytes());
112 let consequence_hash = Blake3Hash(*hasher.finalize().as_bytes());
113
114 let mut receipt = CryptographicReceipt {
115 prev_hash: Blake3Hash([0u8; 32]),
116 discipline_id: uuid::Uuid::nil(),
117 law_id: uuid::Uuid::nil(),
118 consequence_hash,
119 sequence: 1,
120 signature: [0u8; 64],
121 };
122 let payload_hash = receipt.compute_payload_hash();
123 let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
124 receipt.signature = signing_key.sign(&payload_hash.0).to_bytes();
125 receipt
126 }
127
128 fn exit(self) -> CandidateData {
129 self.data
130 }
131
132 fn replay(history: Vec<Self::Receipt>) -> Result<Self, ChainError> {
133 if history.len() < 2 {
134 return Err(ChainError::InsufficientHistory {
135 required: 2,
136 got: history.len(),
137 });
138 }
139 let signing_key = ed25519_dalek::SigningKey::from_bytes(&[0u8; 32]);
140 let verifying_key = signing_key.verifying_key();
141 crate::runtime::control_plane::receipts::verify_receipt_chain(
142 &history,
143 &verifying_key,
144 &history[0].prev_hash,
145 )
146 .map_err(|e| ChainError::HashMismatch {
147 index: 1,
148 expected: "Valid signature".to_string(),
149 got: e.to_string(),
150 })?;
151
152 let graph_hash = bytes_to_hex(&history[1].consequence_hash.0);
153 Ok(Machine::new(
154 CANDIDATE,
155 CandidateData {
156 elements: Vec::new(),
157 quads: Vec::new(),
158 graph_hash,
159 },
160 ))
161 }
162}