@@ -2,10 +2,13 @@ use crate::invariants::common::{InvariantCheckError, RegistrySnapshot};
2
2
3
3
use std:: convert:: TryFrom ;
4
4
5
+ use ic_base_types:: CanisterId ;
5
6
use ic_protobuf:: registry:: routing_table:: v1:: {
6
7
CanisterMigrations as pbCanisterMigrations, RoutingTable as pbRoutingTable,
7
8
} ;
8
- use ic_registry_keys:: { make_canister_migrations_record_key, make_routing_table_record_key} ;
9
+ use ic_registry_keys:: {
10
+ make_canister_migrations_record_key, make_canister_ranges_key, make_routing_table_record_key,
11
+ } ;
9
12
use ic_registry_routing_table:: { CanisterMigrations , RoutingTable } ;
10
13
use prost:: Message ;
11
14
@@ -19,14 +22,40 @@ pub(crate) fn check_routing_table_invariants(
19
22
20
23
// Return routing table from snapshot
21
24
fn get_routing_table ( snapshot : & RegistrySnapshot ) -> RoutingTable {
22
- match snapshot. get ( make_routing_table_record_key ( ) . as_bytes ( ) ) {
23
- Some ( routing_table_bytes) => {
24
- let routing_table_proto =
25
- pbRoutingTable:: decode ( routing_table_bytes. as_slice ( ) ) . unwrap ( ) ;
26
- RoutingTable :: try_from ( routing_table_proto) . unwrap ( )
27
- }
28
- None => panic ! ( "No routing table in snapshot" ) ,
25
+ // TODO(NNS1-3781): Remove this once we have sharded table supported by all clients.
26
+ let rt_from_routing_table_record =
27
+ match snapshot. get ( make_routing_table_record_key ( ) . as_bytes ( ) ) {
28
+ Some ( routing_table_bytes) => {
29
+ let routing_table_proto =
30
+ pbRoutingTable:: decode ( routing_table_bytes. as_slice ( ) ) . unwrap ( ) ;
31
+ RoutingTable :: try_from ( routing_table_proto) . unwrap ( )
32
+ }
33
+ None => panic ! ( "No routing table in snapshot" ) ,
34
+ } ;
35
+
36
+ // If there are shards, they should match the routing table record.
37
+ let shards = get_routing_table_shards ( snapshot) ;
38
+ if !shards. is_empty ( ) {
39
+ let rt_from_shards = RoutingTable :: try_from ( shards) . unwrap ( ) ;
40
+ assert_eq ! (
41
+ rt_from_shards, rt_from_routing_table_record,
42
+ "Routing tables from shards and routing table record do not match."
43
+ ) ;
44
+ }
45
+
46
+ rt_from_routing_table_record
47
+ }
48
+
49
+ fn get_routing_table_shards ( snapshot : & RegistrySnapshot ) -> Vec < pbRoutingTable > {
50
+ let start = make_canister_ranges_key ( CanisterId :: from_u64 ( 0 ) ) . into_bytes ( ) ;
51
+ let end = make_canister_ranges_key ( CanisterId :: from_u64 ( u64:: MAX ) ) . into_bytes ( ) ;
52
+ let mut shards = vec ! [ ] ;
53
+ for ( _, value) in snapshot. range ( start..=end) {
54
+ let routing_table_proto = pbRoutingTable:: decode ( value. as_slice ( ) ) . unwrap ( ) ;
55
+ shards. push ( routing_table_proto) ;
29
56
}
57
+
58
+ shards
30
59
}
31
60
32
61
/// Iff `canister_migrations` is present, check that its invariants hold if reading and conversion succeed.
@@ -291,4 +320,35 @@ mod tests {
291
320
assert ! ( check_routing_table_invariants( & snapshot) . is_ok( ) ) ;
292
321
assert ! ( check_canister_migrations_invariants( & snapshot) . is_err( ) ) ;
293
322
}
323
+
324
+ #[ test]
325
+ #[ should_panic( expected = "Routing tables from shards and routing table record do not match." ) ]
326
+ fn if_sharded_ranges_they_must_match_original_routing_table ( ) {
327
+ let mut snapshot = RegistrySnapshot :: new ( ) ;
328
+
329
+ // The routing table before canister migration.
330
+ let routing_table = RoutingTable :: try_from ( btreemap ! {
331
+ CanisterIdRange { start: CanisterId :: from( 0x0 ) , end: CanisterId :: from( 0xff ) } => subnet_test_id( 1 ) ,
332
+ CanisterIdRange { start: CanisterId :: from( 0x100 ) , end: CanisterId :: from( 0x1ff ) } => subnet_test_id( 2 ) ,
333
+ CanisterIdRange { start: CanisterId :: from( 0x200 ) , end: CanisterId :: from( 0x2ff ) } => subnet_test_id( 3 ) ,
334
+ } ) . unwrap ( ) ;
335
+
336
+ let routing_table = PbRoutingTable :: from ( routing_table) ;
337
+ let key1 = make_routing_table_record_key ( ) ;
338
+ let value1 = routing_table. encode_to_vec ( ) ;
339
+
340
+ let rt_shard = RoutingTable :: try_from ( btreemap ! {
341
+ CanisterIdRange { start: CanisterId :: from( 0x0 ) , end: CanisterId :: from( 0xff ) } => subnet_test_id( 1 ) ,
342
+ CanisterIdRange { start: CanisterId :: from( 0x100 ) , end: CanisterId :: from( 0x1ff ) } => subnet_test_id( 2 ) ,
343
+ } ) . unwrap ( ) ;
344
+
345
+ let rt_shard = PbRoutingTable :: from ( rt_shard) ;
346
+ let key2 = make_canister_ranges_key ( CanisterId :: from_u64 ( 0x0 ) ) ;
347
+ let value2 = rt_shard. encode_to_vec ( ) ;
348
+
349
+ snapshot. insert ( key1. into_bytes ( ) , value1) ;
350
+ snapshot. insert ( key2. into_bytes ( ) , value2) ;
351
+
352
+ check_routing_table_invariants ( & snapshot) . unwrap ( ) ;
353
+ }
294
354
}
0 commit comments