@@ -4,7 +4,9 @@ use crate::invariants::common::RegistrySnapshot;
44use ic_base_types:: SubnetId ;
55use ic_protobuf:: registry:: {
66 node:: v1:: NodeRecord ,
7- subnet:: v1:: { CanisterCyclesCostSchedule , SubnetListRecord , SubnetRecord , SubnetType } ,
7+ subnet:: v1:: {
8+ CanisterCyclesCostSchedule , SubnetFeatures , SubnetListRecord , SubnetRecord , SubnetType ,
9+ } ,
810} ;
911use ic_registry_keys:: { make_subnet_list_record_key, make_subnet_record_key} ;
1012use ic_test_utilities_types:: ids:: { node_test_id, subnet_test_id} ;
@@ -17,6 +19,8 @@ fn only_application_subnets_can_be_free_cycles_cost_schedule() {
1719 setup_minimal_registry_snapshot_for_check_subnet_invariants (
1820 system_subnet_id,
1921 test_subnet_id,
22+ 1 ,
23+ false ,
2024 ) ;
2125
2226 // Trivial case. (Never forget the trivial case, because this is an edge
@@ -54,9 +58,94 @@ fn only_application_subnets_can_be_free_cycles_cost_schedule() {
5458 ) ;
5559}
5660
61+ #[ test]
62+ fn only_sev_enabled_subnets_consist_of_sev_enabled_nodes ( ) {
63+ let system_subnet_id = subnet_test_id ( 1 ) ;
64+ let test_subnet_id = subnet_test_id ( 2 ) ;
65+ let test_node_id = node_test_id ( 103 ) ;
66+
67+ // get a snapshot without chip IDs
68+ let ( mut snapshot, mut test_subnet_record) =
69+ setup_minimal_registry_snapshot_for_check_subnet_invariants (
70+ system_subnet_id,
71+ test_subnet_id,
72+ 4 ,
73+ false ,
74+ ) ;
75+
76+ // a non SEV-enabled subnet only with nodes without chip ID is compliant
77+ check_subnet_invariants ( & snapshot) . unwrap ( ) ;
78+
79+ // a non SEV-enabled subnet with some nodes with and some without chip IDs is compliant
80+ let mut test_node_record = NodeRecord :: default ( ) ;
81+ test_node_record. chip_id = Some ( "a chip id" . into ( ) ) ;
82+ snapshot. insert (
83+ make_node_record_key ( test_node_id) . into_bytes ( ) ,
84+ test_node_record. encode_to_vec ( ) ,
85+ ) ;
86+ check_subnet_invariants ( & snapshot) . unwrap ( ) ;
87+
88+ // an SEV-enabled subnet only with nodes without chip ID is NOT compliant
89+ test_subnet_record. features = Some ( SubnetFeatures {
90+ sev_enabled : Some ( true ) ,
91+ ..Default :: default ( )
92+ } ) ;
93+ snapshot. insert (
94+ make_subnet_record_key ( test_subnet_id) . into_bytes ( ) ,
95+ test_subnet_record. encode_to_vec ( ) ,
96+ ) ;
97+ let mut test_node_record = NodeRecord :: default ( ) ;
98+ test_node_record. chip_id = None ;
99+ snapshot. insert (
100+ make_node_record_key ( test_node_id) . into_bytes ( ) ,
101+ test_node_record. encode_to_vec ( ) ,
102+ ) ;
103+ assert_non_compliant_record (
104+ & snapshot,
105+ "subnet fbysm-3acaa-aaaaa-aaaap-yai is sev-enabled but at least one of its nodes is not" ,
106+ ) ;
107+
108+ // get a snapshot with chip IDs
109+ let ( mut snapshot, mut test_subnet_record) =
110+ setup_minimal_registry_snapshot_for_check_subnet_invariants (
111+ system_subnet_id,
112+ test_subnet_id,
113+ 4 ,
114+ true ,
115+ ) ;
116+
117+ // a non SEV-enabled subnet only with nodes without chip ID is compliant
118+ check_subnet_invariants ( & snapshot) . unwrap ( ) ;
119+
120+ // an SEV-enabled subnet only with nodes with chip ID is compliant
121+ test_subnet_record. features = Some ( SubnetFeatures {
122+ sev_enabled : Some ( true ) ,
123+ ..Default :: default ( )
124+ } ) ;
125+ snapshot. insert (
126+ make_subnet_record_key ( test_subnet_id) . into_bytes ( ) ,
127+ test_subnet_record. encode_to_vec ( ) ,
128+ ) ;
129+ check_subnet_invariants ( & snapshot) . unwrap ( ) ;
130+
131+ // an SEV-enabled subnet with some nodes with and some without chip ID is NOT compliant
132+ let mut test_node_record = NodeRecord :: default ( ) ;
133+ test_node_record. chip_id = None ;
134+ snapshot. insert (
135+ make_node_record_key ( test_node_id) . into_bytes ( ) ,
136+ test_node_record. encode_to_vec ( ) ,
137+ ) ;
138+ assert_non_compliant_record (
139+ & snapshot,
140+ "subnet fbysm-3acaa-aaaaa-aaaap-yai is sev-enabled but at least one of its nodes is not" ,
141+ ) ;
142+ }
143+
57144fn setup_minimal_registry_snapshot_for_check_subnet_invariants (
58145 system_subnet_id : SubnetId ,
59146 test_subnet_id : SubnetId ,
147+ num_nodes_in_test_subnet : usize ,
148+ with_chip_id : bool ,
60149) -> ( RegistrySnapshot , SubnetRecord ) {
61150 let mut snapshot = RegistrySnapshot :: new ( ) ;
62151
@@ -84,11 +173,18 @@ fn setup_minimal_registry_snapshot_for_check_subnet_invariants(
84173 ) ;
85174
86175 // Add a test subnet in the subnet list.
87- let test_node_id = node_test_id ( 100 ) ;
88- snapshot. insert (
89- make_node_record_key ( test_node_id. to_owned ( ) ) . into_bytes ( ) ,
90- NodeRecord :: default ( ) . encode_to_vec ( ) ,
91- ) ;
176+ for i in 0 ..num_nodes_in_test_subnet {
177+ let node_id = node_test_id ( ( i + 100 ) as u64 ) ;
178+ let mut node_record = NodeRecord :: default ( ) ;
179+ if with_chip_id {
180+ node_record. chip_id = Some ( format ! ( "chip-id-{i}" ) . into_bytes ( ) ) ;
181+ }
182+ snapshot. insert (
183+ make_node_record_key ( node_id. to_owned ( ) ) . into_bytes ( ) ,
184+ node_record. encode_to_vec ( ) ,
185+ ) ;
186+ }
187+
92188 let subnet_list_record = SubnetListRecord {
93189 subnets : vec ! [
94190 system_subnet_id. get( ) . into_vec( ) ,
@@ -99,8 +195,12 @@ fn setup_minimal_registry_snapshot_for_check_subnet_invariants(
99195 make_subnet_list_record_key ( ) . into_bytes ( ) ,
100196 subnet_list_record. encode_to_vec ( ) ,
101197 ) ;
198+ let membership = ( 0 ..num_nodes_in_test_subnet)
199+ . map ( |i| node_test_id ( ( i + 100 ) as u64 ) . get ( ) . to_vec ( ) )
200+ . collect ( ) ;
201+
102202 let test_subnet_record = SubnetRecord {
103- membership : vec ! [ test_node_id . get ( ) . to_vec ( ) ] ,
203+ membership : membership ,
104204 ..Default :: default ( )
105205 } ;
106206 snapshot. insert (
@@ -116,5 +216,6 @@ fn assert_non_compliant_record(snapshot: &RegistrySnapshot, error_msg: &str) {
116216 panic ! ( "Expected Err, but got Ok!" ) ;
117217 } ;
118218 let message = err. msg . to_lowercase ( ) ;
219+ println ! ( "Error message: {message}" ) ;
119220 assert ! ( message. contains( error_msg) ) ;
120221}
0 commit comments