1use anyhow::anyhow;
3
4use crate::{
5 common::{
6 crypto::{
7 hash::Hash,
8 signature::{MultiSigned, PublicKey},
9 },
10 key_format::{KeyFormat, KeyFormatAtom},
11 namespace::Namespace,
12 },
13 consensus::{
14 registry::{Node, Runtime},
15 state::StateError,
16 },
17 key_format,
18 storage::mkvs::ImmutableMKVS,
19};
20
21pub struct ImmutableState<'a, T: ImmutableMKVS> {
23 mkvs: &'a T,
24}
25
26impl<'a, T: ImmutableMKVS> ImmutableState<'a, T> {
27 pub fn new(mkvs: &'a T) -> ImmutableState<'a, T> {
29 ImmutableState { mkvs }
30 }
31}
32
33key_format!(SignedNodeKeyFmt, 0x11, Hash);
34key_format!(RuntimeKeyFmt, 0x13, Hash);
35key_format!(SuspendedRuntimeKeyFmt, 0x18, Hash);
36
37impl<'a, T: ImmutableMKVS> ImmutableState<'a, T> {
38 fn decode_node(&self, data: &[u8]) -> Result<Node, StateError> {
39 let signed: MultiSigned =
40 cbor::from_slice(data).map_err(|err| StateError::Unavailable(anyhow!(err)))?;
41 cbor::from_slice_non_strict(&signed.blob)
43 .map_err(|err| StateError::Unavailable(anyhow!(err)))
44 }
45
46 pub fn node(&self, id: &PublicKey) -> Result<Option<Node>, StateError> {
48 let h = Hash::digest_bytes(id.as_ref());
49 match self.mkvs.get(&SignedNodeKeyFmt(h).encode()) {
50 Ok(Some(b)) => Ok(Some(self.decode_node(&b)?)),
51 Ok(None) => Ok(None),
52 Err(err) => Err(StateError::Unavailable(anyhow!(err))),
53 }
54 }
55
56 pub fn nodes(&self) -> Result<Vec<Node>, StateError> {
58 let mut it = self.mkvs.iter();
59 it.seek(&SignedNodeKeyFmt::default().encode_partial(0));
60
61 let mut result: Vec<Node> = Vec::new();
62
63 while let Some(value) = it
64 .next()
65 .and_then(|(key, value)| SignedNodeKeyFmt::decode(&key).map(|_| value))
66 {
67 result.push(self.decode_node(&value)?)
68 }
69
70 Ok(result)
71 }
72
73 fn decode_runtime(&self, data: &[u8]) -> Result<Runtime, StateError> {
74 cbor::from_slice(data).map_err(|err| StateError::Unavailable(anyhow!(err)))
75 }
76
77 pub fn runtime(&self, id: &Namespace) -> Result<Option<Runtime>, StateError> {
83 let h = Hash::digest_bytes(id.as_ref());
84
85 match self.mkvs.get(&RuntimeKeyFmt(h).encode()) {
87 Ok(Some(b)) => Ok(Some(self.decode_runtime(&b)?)),
88 Ok(None) => {
89 match self.mkvs.get(&SuspendedRuntimeKeyFmt(h).encode()) {
91 Ok(Some(b)) => Ok(Some(self.decode_runtime(&b)?)),
92 Ok(None) => Ok(None),
93 Err(err) => Err(StateError::Unavailable(anyhow!(err))),
94 }
95 }
96 Err(err) => Err(StateError::Unavailable(anyhow!(err))),
97 }
98 }
99}
100
101#[cfg(test)]
102mod test {
103 use std::collections::BTreeMap;
104
105 use crate::{
106 common::crypto::signature,
107 consensus::registry::{
108 AnyNodeRuntimeAdmissionPolicy, Capabilities, CapabilityTEE, ConsensusInfo,
109 EntityWhitelistRoleAdmissionPolicy, NodeRuntime, P2PInfo, PerRoleAdmissionPolicy,
110 RolesMask, RuntimeAdmissionPolicy, RuntimeKind, TEEHardware, TLSInfo, VRFInfo,
111 VersionInfo,
112 },
113 storage::mkvs::{
114 interop::{Fixture, ProtocolServer},
115 Root, RootType, Tree,
116 },
117 Version,
118 };
119
120 use super::*;
121
122 #[test]
123 fn test_registry_state_interop() {
124 let server = ProtocolServer::new(Fixture::ConsensusMock.into());
132 let mock_consensus_root = Root {
133 version: 1,
134 root_type: RootType::State,
135 hash: Hash::from("8e39bf193f8a954ab8f8d7cb6388c591fd0785ea060bbd8e3752e266b54499d3"),
136 ..Default::default()
137 };
138 let mkvs = Tree::builder()
139 .with_capacity(100_000, 10_000_000)
140 .with_root(mock_consensus_root)
141 .build(server.read_sync());
142 let registry_state = ImmutableState::new(&mkvs);
143
144 let nodes = registry_state.nodes().expect("nodes query should work");
146 assert_eq!(
147 nodes.len(),
148 2,
149 "expected number of nodes should be returned"
150 );
151
152 let expected_nodes = vec![
153 Node{
154 v: 3,
155 id: signature::PublicKey::from("43e5aaee54c768867718837ef4f6a6161e0615da0fcf8da394e5c8b7a0d54c18"),
156 entity_id: signature::PublicKey::from("761950dfe65936f6e9d06a0124bc930f7d5b1812ceefdfb2cae0ef5841291531"),
157 expiration: 32,
158 ..Default::default()
159 },
160 Node{
161 v: 3,
162 id: signature::PublicKey::from("f43c3559658f76b85d0630f56dc75d603807ac60be0ca3aada66799289066758"),
163 entity_id: signature::PublicKey::from("761950dfe65936f6e9d06a0124bc930f7d5b1812ceefdfb2cae0ef5841291531"),
164 expiration: 32,
165 tls: TLSInfo{
166 pub_key: signature::PublicKey::from("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"),
167 ..Default::default()
168 },
169 p2p: P2PInfo{
170 id: signature::PublicKey::from("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3"),
171 addresses: Some(Vec::new()),
172 },
173 consensus: ConsensusInfo{
174 id: signature::PublicKey::from("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4"),
175 addresses: Some(Vec::new()),
176 },
177 vrf: VRFInfo{
178 id: PublicKey::from("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5"),
179 },
180 runtimes: Some(vec![
181 NodeRuntime{
182 id: Namespace::from("8000000000000000000000000000000000000000000000000000000000000010"),
183 version: Version::from(321),
184 ..Default::default()
185 },
186 NodeRuntime{
187 id: Namespace::from("8000000000000000000000000000000000000000000000000000000000000011"),
188 version: Version::from(123),
189 capabilities: Capabilities{
190 tee: Some(CapabilityTEE{
191 hardware: TEEHardware::TEEHardwareIntelSGX,
192 rak: signature::PublicKey::from("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8"),
193 attestation: vec![0, 1,2,3,4,5],
194 ..Default::default()
195 }),
196 },
197 extra_info: Some(vec![5,3,2,1]),
198 },
199 ]),
200 ..Default::default()
201 },
202 ];
203 assert_eq!(nodes, expected_nodes,);
204
205 let node = registry_state
206 .node(&expected_nodes.get(1).unwrap().id)
207 .expect("node query should work");
208 assert_eq!(node, Some(expected_nodes.get(1).unwrap().clone()));
209
210 let node = registry_state
211 .node(&signature::PublicKey::from(
212 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
213 ))
214 .expect("node query should work");
215 assert_eq!(node, None);
216
217 let expected_runtimes = vec![
218 Runtime {
219 v: 3,
220 id: Namespace::from(
221 "8000000000000000000000000000000000000000000000000000000000000010",
222 ),
223 entity_id: signature::PublicKey::from(
224 "761950dfe65936f6e9d06a0124bc930f7d5b1812ceefdfb2cae0ef5841291531",
225 ),
226 kind: RuntimeKind::KindCompute,
227 tee_hardware: TEEHardware::TEEHardwareInvalid,
228 admission_policy: RuntimeAdmissionPolicy {
229 any_node: Some(AnyNodeRuntimeAdmissionPolicy {}),
230 ..Default::default()
231 },
232 deployments: vec![
233 VersionInfo {
234 version: Version::from(321),
235 valid_from: 42,
236 ..Default::default()
237 },
238 VersionInfo {
239 version: Version::from(320),
240 valid_from: 10,
241 ..Default::default()
242 },
243 ],
244 ..Default::default()
245 },
246 Runtime {
247 v: 3,
248 id: Namespace::from(
249 "8000000000000000000000000000000000000000000000000000000000000011",
250 ),
251 entity_id: signature::PublicKey::from(
252 "761950dfe65936f6e9d06a0124bc930f7d5b1812ceefdfb2cae0ef5841291531",
253 ),
254 kind: RuntimeKind::KindCompute,
255 tee_hardware: TEEHardware::TEEHardwareIntelSGX,
256 admission_policy: RuntimeAdmissionPolicy {
257 any_node: Some(AnyNodeRuntimeAdmissionPolicy {}),
258 ..Default::default()
259 },
260 deployments: vec![
261 VersionInfo {
262 version: Version::from(123),
263 valid_from: 42,
264 tee: vec![1, 2, 3, 4, 5],
265 bundle_checksum: vec![0x5; 32],
266 },
267 VersionInfo {
268 version: Version::from(120),
269 valid_from: 10,
270 tee: vec![5, 4, 3, 2, 1],
271 ..Default::default()
272 },
273 ],
274 ..Default::default()
275 },
276 Runtime {
277 v: 3,
278 id: Namespace::from(
279 "8000000000000000000000000000000000000000000000000000000000000012",
280 ),
281 entity_id: signature::PublicKey::from(
282 "761950dfe65936f6e9d06a0124bc930f7d5b1812ceefdfb2cae0ef5841291531",
283 ),
284 kind: RuntimeKind::KindCompute,
285 tee_hardware: TEEHardware::TEEHardwareIntelSGX,
286 admission_policy: RuntimeAdmissionPolicy {
287 per_role: BTreeMap::from([(
288 RolesMask::ROLE_OBSERVER,
289 PerRoleAdmissionPolicy {
290 entity_whitelist: Some(EntityWhitelistRoleAdmissionPolicy {
291 entities: BTreeMap::new(),
292 }),
293 },
294 )]),
295 ..Default::default()
296 },
297 deployments: vec![VersionInfo {
298 version: Version::from(123),
299 valid_from: 42,
300 tee: vec![1, 2, 3, 4, 5],
301 bundle_checksum: vec![0x5; 32],
302 }],
303 ..Default::default()
304 },
305 ];
306
307 for rt in expected_runtimes {
308 let ext_rt = registry_state
309 .runtime(&rt.id)
310 .expect("runtime query should work");
311 assert_eq!(ext_rt, Some(rt));
312 }
313 }
314}