aleph_types/message/
instance.rs

1use crate::message::execution::base::ExecutableContent;
2use crate::message::execution::environment::InstanceEnvironment;
3use crate::message::execution::volume::RootfsVolume;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct InstanceContent {
8    #[serde(flatten)]
9    base: ExecutableContent,
10    /// Properties of the instance execution environment.
11    environment: InstanceEnvironment,
12    /// Root filesystem for the instance.
13    rootfs: RootfsVolume,
14}
15
16#[cfg(test)]
17mod test {
18    use super::*;
19    use crate::chain::Chain;
20    use crate::message::base_message::{MessageConfirmation, MessageContentEnum};
21    use crate::message::execution::base::{Payment, PaymentType};
22    use crate::message::execution::environment::{
23        GpuDeviceClass, GpuProperties, HostRequirements, Hypervisor, MachineResources,
24        NodeRequirements,
25    };
26    use crate::message::execution::volume::{ParentVolume, VolumePersistence};
27    use crate::message::{ContentSource, Message, MessageType};
28    use crate::storage_size::{MemorySize, MiB};
29    use crate::timestamp::Timestamp;
30    use crate::{address, channel, item_hash, signature};
31    use assert_matches::assert_matches;
32    use std::collections::HashMap;
33
34    const INSTANCE_PAYG_FIXTURE: &str = include_str!(concat!(
35        env!("CARGO_MANIFEST_DIR"),
36        "/../../fixtures/messages/instance/instance-gpu-payg.json"
37    ));
38
39    #[test]
40    fn test_deserialize_instance_message() {
41        let message: Message = serde_json::from_str(INSTANCE_PAYG_FIXTURE).unwrap();
42
43        assert_eq!(
44            message.sender,
45            address!("0x238224C744F4b90b4494516e074D2676ECfC6803")
46        );
47        assert_eq!(message.chain, Chain::Ethereum);
48        assert_eq!(
49            message.signature,
50            signature!(
51                "0x4f7250efd67d989ac3067358ee657e301cd437fd0b4acb38342402e60125a0a209818f555386cd17b82080aba0a7a5cd83e4e1d8875c58b38f2e64cbe5dd308f1c"
52            )
53        );
54        assert_matches!(message.message_type, MessageType::Instance);
55        assert_matches!(
56            message.content_source,
57            ContentSource::Inline { item_content: _ }
58        );
59        assert_eq!(
60            message.item_hash,
61            item_hash!("a41fb91c3e68370759b72338dd1947f18e2ed883837aec5dc731d5f427f90564")
62        );
63        assert_eq!(message.time, Timestamp::from(1762349117.833245));
64        assert_eq!(message.channel, Some(channel!("ALEPH-CLOUDSOLUTIONS")));
65
66        // Check content fields
67        assert_eq!(
68            &message.content.address,
69            &address!("0x238224C744F4b90b4494516e074D2676ECfC6803")
70        );
71        assert_eq!(&message.content.time, &Timestamp::from(1762349117.833176));
72
73        // Check instance content fields
74        let instance_content = match message.content() {
75            MessageContentEnum::Instance(content) => content,
76            other => {
77                panic!("Expected MessageContentEnum::Instance, got {:?}", other);
78            }
79        };
80
81        assert!(!instance_content.base.allow_amend);
82        assert_eq!(
83            instance_content.base.metadata,
84            Some(HashMap::from([(
85                "name".to_string(),
86                serde_json::Value::String("gpu-l40s-2".to_string())
87            )]))
88        );
89        assert_eq!(instance_content.base.variables, None);
90        assert_eq!(
91            instance_content.base.resources,
92            MachineResources {
93                vcpus: 12,
94                memory: MiB::from_units(73728),
95                seconds: 30,
96                published_ports: None,
97            }
98        );
99        assert_eq!(
100            instance_content.base.authorized_keys,
101            Some(vec![
102                "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC068SD08xlTtMxTdmCe3rPVM/uA7SvgDUiQwP0FrIGS Libertai".to_string()
103            ])
104        );
105        assert_eq!(
106            instance_content.environment,
107            InstanceEnvironment {
108                internet: true,
109                aleph_api: true,
110                hypervisor: Some(Hypervisor::Qemu),
111                trusted_execution: None,
112                reproducible: false,
113                shared_cache: false,
114            }
115        );
116
117        let expected_requirements = HostRequirements {
118            cpu: None,
119            node: Some(NodeRequirements {
120                owner: None,
121                address_regex: None,
122                node_hash: Some(
123                    "dc3d1d194a990b5c54380c3c0439562fefa42f5a46807cba1c500ec3affecf04".to_string(),
124                ),
125                terms_and_conditions: None,
126            }),
127            gpu: Some(vec![GpuProperties {
128                vendor: "NVIDIA".to_string(),
129                device_name: "AD102GL [L40S]".to_string(),
130                device_class: GpuDeviceClass::_3DController,
131                device_id: "10de:26b9".to_string(),
132            }]),
133        };
134
135        assert_eq!(
136            instance_content.base.payment,
137            Some(Payment {
138                chain: Some(Chain::Base),
139                receiver: Some(address!("0xf0c0ddf11a0dCE6618B5DF8d9fAE3D95e72E04a9")),
140                payment_type: PaymentType::Superfluid,
141            })
142        );
143        assert_eq!(
144            instance_content.base.requirements,
145            Some(expected_requirements)
146        );
147        assert!(instance_content.base.volumes.is_empty());
148        assert_eq!(instance_content.base.replaces, None);
149        assert_eq!(
150            instance_content.rootfs,
151            RootfsVolume {
152                parent: ParentVolume {
153                    reference: item_hash!(
154                        "b6ff5c3a8205d1ca4c7c3369300eeafff498b558f71b851aa2114afd0a532717"
155                    ),
156                    use_latest: true
157                },
158                persistence: VolumePersistence::Host,
159                size_mib: MiB::from_units(737280).into(),
160                forgotten_by: None,
161            }
162        );
163
164        assert!(message.confirmed());
165        assert_eq!(
166            message.confirmations,
167            vec![MessageConfirmation {
168                chain: Chain::Ethereum,
169                height: 23733404,
170                hash: "0xda1dd1676b5f08cef019172a7b31de303c86aafe8cb209916cf5ffa2bc5871dc"
171                    .to_string(),
172                time: None,
173                publisher: None,
174            }]
175        );
176    }
177}