@@ -2,6 +2,7 @@ use assert_matches::assert_matches;
2
2
use ic_config:: { execution_environment:: Config as HypervisorConfig , subnet_config:: SubnetConfig } ;
3
3
use ic_error_types:: RejectCode ;
4
4
use ic_management_canister_types:: { CanisterSettingsArgsBuilder , CanisterStatusType } ;
5
+ use ic_management_canister_types:: { CanisterUpgradeOptions , WasmMemoryPersistence } ;
5
6
use ic_registry_subnet_type:: SubnetType ;
6
7
use ic_replicated_state:: canister_state:: NextExecution ;
7
8
use ic_replicated_state:: canister_state:: WASM_PAGE_SIZE_IN_BYTES ;
@@ -823,6 +824,7 @@ fn global_timer_produces_transient_error_on_out_of_cycles() {
823
824
fn get_wat_with_update_and_hook_mem_grow (
824
825
update_grow_mem_size : i32 ,
825
826
hook_grow_mem_size : i32 ,
827
+ with_enchanced_ortogonal_persistence : bool ,
826
828
) -> String {
827
829
let mut wat = r#"
828
830
(module
@@ -843,7 +845,17 @@ fn get_wat_with_update_and_hook_mem_grow(
843
845
wat. push_str (
844
846
r#")))
845
847
)
846
- (memory 1 20)
848
+ (memory 1 20)"# ,
849
+ ) ;
850
+ if with_enchanced_ortogonal_persistence {
851
+ wat. push_str (
852
+ r#"
853
+ (@custom "icp:private enhanced-orthogonal-persistence" "")
854
+ "# ,
855
+ ) ;
856
+ }
857
+ wat. push_str (
858
+ r#"
847
859
)"# ,
848
860
) ;
849
861
wat
@@ -856,7 +868,8 @@ fn on_low_wasm_memory_is_executed() {
856
868
let update_grow_mem_size = 7 ;
857
869
let hook_grow_mem_size = 5 ;
858
870
859
- let wat = get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size) ;
871
+ let wat =
872
+ get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size, false ) ;
860
873
861
874
let canister_id = test. canister_from_wat ( wat. as_str ( ) ) . unwrap ( ) ;
862
875
@@ -905,7 +918,8 @@ fn on_low_wasm_memory_is_executed_before_message() {
905
918
let update_grow_mem_size = 7 ;
906
919
let hook_grow_mem_size = 5 ;
907
920
908
- let wat = get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size) ;
921
+ let wat =
922
+ get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size, false ) ;
909
923
910
924
let canister_id = test. canister_from_wat ( wat. as_str ( ) ) . unwrap ( ) ;
911
925
@@ -955,14 +969,178 @@ fn on_low_wasm_memory_is_executed_before_message() {
955
969
) ;
956
970
}
957
971
972
+ #[ test]
973
+ fn on_low_wasm_memory_is_executed_after_upgrade_if_condition_holds ( ) {
974
+ let mut test = ExecutionTestBuilder :: new ( ) . with_manual_execution ( ) . build ( ) ;
975
+
976
+ let update_grow_mem_size = 7 ;
977
+ let hook_grow_mem_size = 5 ;
978
+
979
+ let wat: String =
980
+ get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size, true ) ;
981
+
982
+ let canister_id = test. canister_from_wat ( wat. as_str ( ) ) . unwrap ( ) ;
983
+
984
+ test. canister_update_wasm_memory_limit_and_wasm_memory_threshold (
985
+ canister_id,
986
+ ( 20 * WASM_PAGE_SIZE_IN_BYTES as u64 ) . into ( ) ,
987
+ ( 15 * WASM_PAGE_SIZE_IN_BYTES as u64 ) . into ( ) ,
988
+ )
989
+ . unwrap ( ) ;
990
+
991
+ // Here we have:
992
+ // wasm_capacity = wasm_memory_limit = 20 Wasm Pages
993
+ // wasm_memory_threshold = 15 Wasm Pages
994
+
995
+ // Initially wasm_memory.size = 1
996
+ assert_eq ! (
997
+ test. execution_state( canister_id) . wasm_memory. size,
998
+ NumWasmPages :: new( 1 )
999
+ ) ;
1000
+
1001
+ test. ingress_raw ( canister_id, "grow_mem" , vec ! [ ] ) ;
1002
+ test. ingress_raw ( canister_id, "grow_mem" , vec ! [ ] ) ;
1003
+
1004
+ // First ingress messages gets executed.
1005
+ // wasm_memory.size = 1 + 7 = 8
1006
+ // wasm_capacity - used_wasm_memory < self.wasm_memory_threshold
1007
+ // Hook condition is triggered.
1008
+ test. execute_slice ( canister_id) ;
1009
+ assert_eq ! (
1010
+ test. execution_state( canister_id) . wasm_memory. size,
1011
+ NumWasmPages :: new( 8 )
1012
+ ) ;
1013
+
1014
+ let result = test. upgrade_canister_v2 (
1015
+ canister_id,
1016
+ wat:: parse_str ( wat) . unwrap ( ) ,
1017
+ CanisterUpgradeOptions {
1018
+ skip_pre_upgrade : None ,
1019
+ wasm_memory_persistence : Some ( WasmMemoryPersistence :: Keep ) ,
1020
+ } ,
1021
+ ) ;
1022
+ assert_eq ! ( result, Ok ( ( ) ) ) ;
1023
+
1024
+ // Upgrade is executed, and the wasm_memory size is unchanged.
1025
+ // Hook condition is triggered.
1026
+ assert_eq ! (
1027
+ test. execution_state( canister_id) . wasm_memory. size,
1028
+ NumWasmPages :: new( 8 )
1029
+ ) ;
1030
+
1031
+ // Though we have the second ingress message awaiting to be processed,
1032
+ // hook will be executed first.
1033
+ test. execute_slice ( canister_id) ;
1034
+ assert_eq ! (
1035
+ test. execution_state( canister_id) . wasm_memory. size,
1036
+ NumWasmPages :: new( 13 )
1037
+ ) ;
1038
+
1039
+ // The second ingress message is executed after the hook.
1040
+ test. execute_slice ( canister_id) ;
1041
+ assert_eq ! (
1042
+ test. execution_state( canister_id) . wasm_memory. size,
1043
+ NumWasmPages :: new( 20 )
1044
+ ) ;
1045
+ }
1046
+
1047
+ #[ test]
1048
+ fn on_low_wasm_memory_is_not_executed_after_upgrade_if_condition_becomes_unsatisfied ( ) {
1049
+ let mut test = ExecutionTestBuilder :: new ( ) . with_manual_execution ( ) . build ( ) ;
1050
+
1051
+ let update_grow_mem_size = 3 ;
1052
+ let hook_grow_mem_size = 5 ;
1053
+
1054
+ let wat: String =
1055
+ get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size, false ) ;
1056
+
1057
+ let canister_id = test. canister_from_wat ( wat. as_str ( ) ) . unwrap ( ) ;
1058
+
1059
+ test. canister_update_wasm_memory_limit_and_wasm_memory_threshold (
1060
+ canister_id,
1061
+ ( 20 * WASM_PAGE_SIZE_IN_BYTES as u64 ) . into ( ) ,
1062
+ ( 15 * WASM_PAGE_SIZE_IN_BYTES as u64 ) . into ( ) ,
1063
+ )
1064
+ . unwrap ( ) ;
1065
+
1066
+ // Here we have:
1067
+ // wasm_capacity = wasm_memory_limit = 20 Wasm Pages
1068
+ // wasm_memory_threshold = 15 Wasm Pages
1069
+
1070
+ // Initially wasm_memory.size = 1
1071
+ assert_eq ! (
1072
+ test. execution_state( canister_id) . wasm_memory. size,
1073
+ NumWasmPages :: new( 1 )
1074
+ ) ;
1075
+
1076
+ test. ingress_raw ( canister_id, "grow_mem" , vec ! [ ] ) ;
1077
+ test. ingress_raw ( canister_id, "grow_mem" , vec ! [ ] ) ;
1078
+ test. ingress_raw ( canister_id, "grow_mem" , vec ! [ ] ) ;
1079
+
1080
+ // First ingress messages gets executed.
1081
+ // wasm_memory.size = 1 + 3 = 4
1082
+ // wasm_capacity - used_wasm_memory > self.wasm_memory_threshold
1083
+ // Hook condition is not triggered.
1084
+ test. execute_slice ( canister_id) ;
1085
+ assert_eq ! (
1086
+ test. execution_state( canister_id) . wasm_memory. size,
1087
+ NumWasmPages :: new( 4 )
1088
+ ) ;
1089
+
1090
+ // Second ingress messages gets executed.
1091
+ // wasm_memory.size = 4 + 3 = 7
1092
+ // wasm_capacity - used_wasm_memory < self.wasm_memory_threshold
1093
+ // Hook condition is triggered.
1094
+ test. execute_slice ( canister_id) ;
1095
+ assert_eq ! (
1096
+ test. execution_state( canister_id) . wasm_memory. size,
1097
+ NumWasmPages :: new( 7 )
1098
+ ) ;
1099
+ println ! ( "canister upgrade" ) ;
1100
+
1101
+ let result = test. upgrade_canister_v2 (
1102
+ canister_id,
1103
+ wat:: parse_str ( wat) . unwrap ( ) ,
1104
+ CanisterUpgradeOptions {
1105
+ skip_pre_upgrade : None ,
1106
+ wasm_memory_persistence : None ,
1107
+ } ,
1108
+ ) ;
1109
+ assert_eq ! ( result, Ok ( ( ) ) ) ;
1110
+ println ! ( "canister upgrade" ) ;
1111
+
1112
+ // Upgrade is executed, and the wasm_memory size reset to 1.
1113
+ // Hook condition is not triggered.
1114
+ assert_eq ! (
1115
+ test. execution_state( canister_id) . wasm_memory. size,
1116
+ NumWasmPages :: new( 1 )
1117
+ ) ;
1118
+
1119
+ // Though the hook was initially scheduled, it is now removed
1120
+ // from queue, and the third ingress message will be executed.
1121
+ test. execute_slice ( canister_id) ;
1122
+ assert_eq ! (
1123
+ test. execution_state( canister_id) . wasm_memory. size,
1124
+ NumWasmPages :: new( 4 )
1125
+ ) ;
1126
+
1127
+ // There are no messages left to be executed.
1128
+ test. execute_slice ( canister_id) ;
1129
+ assert_eq ! (
1130
+ test. execution_state( canister_id) . wasm_memory. size,
1131
+ NumWasmPages :: new( 4 )
1132
+ ) ;
1133
+ }
1134
+
958
1135
#[ test]
959
1136
fn on_low_wasm_memory_is_executed_once ( ) {
960
1137
let mut test = ExecutionTestBuilder :: new ( ) . build ( ) ;
961
1138
962
1139
let update_grow_mem_size = 7 ;
963
1140
let hook_grow_mem_size = 2 ;
964
1141
965
- let wat = get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size) ;
1142
+ let wat =
1143
+ get_wat_with_update_and_hook_mem_grow ( update_grow_mem_size, hook_grow_mem_size, false ) ;
966
1144
967
1145
let canister_id = test. canister_from_wat ( wat. as_str ( ) ) . unwrap ( ) ;
968
1146
0 commit comments