1
1
use crate :: {
2
2
as_num_instructions,
3
3
canister_manager:: {
4
- uninstall_canister, CanisterManager , CanisterManagerError , CanisterMgrConfig ,
5
- InstallCodeContext , StopCanisterResult ,
4
+ uninstall_canister, AddCanisterChangeToHistory , CanisterManager , CanisterManagerError ,
5
+ CanisterMgrConfig , InstallCodeContext , StopCanisterResult ,
6
6
} ,
7
7
canister_settings:: { CanisterSettings , CanisterSettingsBuilder } ,
8
8
execution_environment:: as_round_instructions,
@@ -20,9 +20,9 @@ use ic_constants::SMALL_APP_SUBNET_MAX_SIZE;
20
20
use ic_cycles_account_manager:: CyclesAccountManager ;
21
21
use ic_error_types:: { ErrorCode , UserError } ;
22
22
use ic_ic00_types:: {
23
- CanisterChangeOrigin , CanisterIdRecord , CanisterInstallMode , CanisterSettingsArgsBuilder ,
24
- CanisterStatusType , CreateCanisterArgs , EmptyBlob , InstallCodeArgs , Method , Payload ,
25
- UpdateSettingsArgs ,
23
+ CanisterChange , CanisterChangeDetails , CanisterChangeOrigin , CanisterIdRecord ,
24
+ CanisterInstallMode , CanisterSettingsArgsBuilder , CanisterStatusType , CreateCanisterArgs ,
25
+ EmptyBlob , InstallCodeArgs , Method , Payload , UpdateSettingsArgs ,
26
26
} ;
27
27
use ic_interfaces:: {
28
28
execution_environment:: {
@@ -72,7 +72,7 @@ use ic_types::{
72
72
use ic_wasm_types:: { CanisterModule , WasmValidationError } ;
73
73
use lazy_static:: lazy_static;
74
74
use maplit:: { btreemap, btreeset} ;
75
- use std:: { collections:: BTreeSet , convert:: TryFrom , sync:: Arc } ;
75
+ use std:: { collections:: BTreeSet , convert:: TryFrom , mem :: size_of , sync:: Arc } ;
76
76
77
77
use super :: InstallCodeResult ;
78
78
use prometheus:: IntCounter ;
@@ -763,8 +763,16 @@ fn upgrading_canister_makes_subnet_oversubscribed() {
763
763
fn install_canister_fails_if_memory_capacity_exceeded ( ) {
764
764
let initial_cycles = Cycles :: new ( 1_000_000_000_000_000 ) ;
765
765
let mb = 1 << 20 ;
766
+ // canister history memory usage for canister1 at the beginning of install_code
767
+ let canister_history_memory_usage = size_of :: < CanisterChange > ( ) + size_of :: < PrincipalId > ( ) ;
766
768
let memory_capacity = 1000 * mb;
767
- let memory_used = memory_capacity - 10 * mb;
769
+ // canister1 memory usage before code change: `canister_history_memory_usage`
770
+ // canister1 memory usage after code change: `memory_used`
771
+ // => SubnetAvailableMemory decreases by `memory_used - canister_history_memory_usage`
772
+ // after canister1 code change and then SubnetAvailableMemory is equal to
773
+ // `memory_capacity - (memory_used - canister_history_memory_usage)`;
774
+ // we want this quantity to be `10 * mb` and derive the value of `memory_used` from there.
775
+ let memory_used = memory_capacity - 10 * mb + ( canister_history_memory_usage as u64 ) ;
768
776
769
777
let wat = r#"
770
778
(module
@@ -2599,8 +2607,12 @@ fn installing_a_canister_with_not_enough_memory_allocation_fails() {
2599
2607
. 0
2600
2608
. unwrap ( ) ;
2601
2609
2602
- // Give just 10 bytes of memory allocation which should result in an error.
2603
- let memory_allocation = MemoryAllocation :: try_from ( NumBytes :: from ( 10 ) ) . unwrap ( ) ;
2610
+ // Give just 10 bytes of memory allocation on top of canister history memory usage
2611
+ // at the beginning of install_code which should result in an error.
2612
+ let canister_history_memory = size_of :: < CanisterChange > ( ) + size_of :: < PrincipalId > ( ) ;
2613
+ let memory_allocation =
2614
+ MemoryAllocation :: try_from ( NumBytes :: from ( canister_history_memory as u64 + 10 ) )
2615
+ . unwrap ( ) ;
2604
2616
let res = install_code (
2605
2617
& canister_manager,
2606
2618
InstallCodeContextBuilder :: default ( )
@@ -2645,7 +2657,12 @@ fn installing_a_canister_with_not_enough_memory_allocation_fails() {
2645
2657
2646
2658
// Attempt to re-install with low memory allocation should fail.
2647
2659
let instructions_before_reinstall = as_num_instructions ( round_limits. instructions ) ;
2648
- let memory_allocation = MemoryAllocation :: try_from ( NumBytes :: from ( 50 ) ) . unwrap ( ) ;
2660
+ // Give just 50 bytes of memory allocation on top of canister history memory usage
2661
+ // at the beginning of install_code which should result in an error.
2662
+ let canister_history_memory = 2 * size_of :: < CanisterChange > ( ) + size_of :: < PrincipalId > ( ) ;
2663
+ let memory_allocation =
2664
+ MemoryAllocation :: try_from ( NumBytes :: from ( canister_history_memory as u64 + 50 ) )
2665
+ . unwrap ( ) ;
2649
2666
let res = install_code (
2650
2667
& canister_manager,
2651
2668
InstallCodeContextBuilder :: default ( )
@@ -2849,7 +2866,7 @@ fn uninstall_canister_doesnt_respond_to_responded_call_contexts() {
2849
2866
. with_call_context( CallContextBuilder :: new( ) . with_responded( true ) . build( ) )
2850
2867
. build( ) ,
2851
2868
mock_time( ) ,
2852
- None ,
2869
+ AddCanisterChangeToHistory :: No ,
2853
2870
) ,
2854
2871
Vec :: new( )
2855
2872
) ;
@@ -2873,7 +2890,7 @@ fn uninstall_canister_responds_to_unresponded_call_contexts() {
2873
2890
)
2874
2891
. build( ) ,
2875
2892
mock_time( ) ,
2876
- None ,
2893
+ AddCanisterChangeToHistory :: No ,
2877
2894
) [ 0 ] ,
2878
2895
Response :: Ingress ( IngressResponse {
2879
2896
message_id: message_test_id( 456 ) ,
@@ -3357,6 +3374,7 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3357
3374
. sender ( controller. into ( ) )
3358
3375
. canister_id ( canister_id)
3359
3376
. build ( ) ;
3377
+ let module_hash = ctxt. wasm_module . module_hash ( ) ;
3360
3378
let ( instructions_left, res, canister) =
3361
3379
install_code ( & canister_manager, ctxt, & mut state, & mut round_limits) ;
3362
3380
state. put_canister_state ( canister. unwrap ( ) ) ;
@@ -3367,7 +3385,8 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3367
3385
// No heap delta.
3368
3386
assert_eq ! ( res. unwrap( ) . heap_delta, NumBytes :: from( 0 ) ) ;
3369
3387
3370
- // Verify the system state is preserved except for certified data, global timer, and canister version.
3388
+ // Verify the system state is preserved except for certified data, global timer,
3389
+ // canister version, and canister history.
3371
3390
let new_state = state
3372
3391
. canister_state ( & canister_id)
3373
3392
. unwrap ( )
@@ -3376,6 +3395,11 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3376
3395
original_canister. system_state . certified_data = Vec :: new ( ) ;
3377
3396
original_canister. system_state . global_timer = CanisterTimer :: Inactive ;
3378
3397
original_canister. system_state . canister_version += 1 ;
3398
+ original_canister. system_state . add_canister_change (
3399
+ state. time ( ) ,
3400
+ canister_change_origin_from_canister ( & controller) ,
3401
+ CanisterChangeDetails :: code_deployment ( CanisterInstallMode :: Install , module_hash) ,
3402
+ ) ;
3379
3403
assert_eq ! ( new_state, original_canister. system_state) ;
3380
3404
3381
3405
// Verify the scheduler state is preserved.
@@ -3392,6 +3416,7 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3392
3416
. sender ( controller. into ( ) )
3393
3417
. canister_id ( canister_id)
3394
3418
. build ( ) ;
3419
+ let module_hash = ctxt. wasm_module . module_hash ( ) ;
3395
3420
let ( instructions_left, res, canister) =
3396
3421
install_code ( & canister_manager, ctxt, & mut state, & mut round_limits) ;
3397
3422
state. put_canister_state ( canister. unwrap ( ) ) ;
@@ -3405,7 +3430,8 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3405
3430
// No heap delta.
3406
3431
assert_eq ! ( res. unwrap( ) . heap_delta, NumBytes :: from( 0 ) ) ;
3407
3432
3408
- // Verify the system state is preserved except for certified data, global timer, and canister version.
3433
+ // Verify the system state is preserved except for certified data, global timer,
3434
+ // canister version, and canister history.
3409
3435
let new_state = state
3410
3436
. canister_state ( & canister_id)
3411
3437
. unwrap ( )
@@ -3414,6 +3440,11 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3414
3440
original_canister. system_state . certified_data = Vec :: new ( ) ;
3415
3441
original_canister. system_state . global_timer = CanisterTimer :: Inactive ;
3416
3442
original_canister. system_state . canister_version += 1 ;
3443
+ original_canister. system_state . add_canister_change (
3444
+ state. time ( ) ,
3445
+ canister_change_origin_from_canister ( & controller) ,
3446
+ CanisterChangeDetails :: code_deployment ( CanisterInstallMode :: Reinstall , module_hash) ,
3447
+ ) ;
3417
3448
assert_eq ! ( new_state, original_canister. system_state) ;
3418
3449
3419
3450
// Verify the scheduler state is preserved.
@@ -3436,6 +3467,7 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3436
3467
. sender ( controller. into ( ) )
3437
3468
. canister_id ( canister_id)
3438
3469
. build ( ) ;
3470
+ let module_hash = ctxt. wasm_module . module_hash ( ) ;
3439
3471
let ( instructions_left, res, canister) =
3440
3472
install_code ( & canister_manager, ctxt, & mut state, & mut round_limits) ;
3441
3473
state. put_canister_state ( canister. unwrap ( ) ) ;
@@ -3449,14 +3481,20 @@ fn install_code_preserves_system_state_and_scheduler_state() {
3449
3481
// No heap delta.
3450
3482
assert_eq ! ( res. unwrap( ) . heap_delta, NumBytes :: from( 0 ) ) ;
3451
3483
3452
- // Verify the system state is preserved except for global timer and canister version.
3484
+ // Verify the system state is preserved except for global timer,
3485
+ // canister version, and canister history.
3453
3486
let new_state = state
3454
3487
. canister_state ( & canister_id)
3455
3488
. unwrap ( )
3456
3489
. system_state
3457
3490
. clone ( ) ;
3458
3491
original_canister. system_state . global_timer = CanisterTimer :: Inactive ;
3459
3492
original_canister. system_state . canister_version += 1 ;
3493
+ original_canister. system_state . add_canister_change (
3494
+ state. time ( ) ,
3495
+ canister_change_origin_from_canister ( & controller) ,
3496
+ CanisterChangeDetails :: code_deployment ( CanisterInstallMode :: Upgrade , module_hash) ,
3497
+ ) ;
3460
3498
assert_eq ! ( new_state, original_canister. system_state) ;
3461
3499
3462
3500
// Verify the scheduler state is preserved.
@@ -3634,9 +3672,14 @@ fn test_upgrade_when_updating_memory_allocation_via_canister_settings() {
3634
3672
compute_allocation_used : state. total_compute_allocation ( ) ,
3635
3673
} ;
3636
3674
let sender = canister_test_id ( 100 ) . get ( ) ;
3675
+ // canister history memory usage at the beginning of attempted upgrade
3676
+ let canister_history_memory = 2 * size_of :: < CanisterChange > ( ) + size_of :: < PrincipalId > ( ) ;
3637
3677
let settings = CanisterSettingsBuilder :: new ( )
3638
3678
. with_memory_allocation (
3639
- MemoryAllocation :: try_from ( NumBytes :: from ( WASM_PAGE_SIZE_IN_BYTES + 100 ) ) . unwrap ( ) ,
3679
+ MemoryAllocation :: try_from ( NumBytes :: from (
3680
+ WASM_PAGE_SIZE_IN_BYTES + 100 + canister_history_memory as u64 ,
3681
+ ) )
3682
+ . unwrap ( ) ,
3640
3683
)
3641
3684
. build ( ) ;
3642
3685
let wat = r#"
@@ -3705,12 +3748,16 @@ fn test_upgrade_when_updating_memory_allocation_via_canister_settings() {
3705
3748
) ;
3706
3749
state. put_canister_state ( res. 2 . unwrap ( ) ) ;
3707
3750
3751
+ // canister history memory usage at the beginning of update_settings
3752
+ let canister_history_memory = 2 * size_of :: < CanisterChange > ( ) + size_of :: < PrincipalId > ( ) ;
3708
3753
// Update memory allocation to a big enough value via canister settings. The
3709
3754
// upgrade should succeed.
3710
3755
let settings = CanisterSettingsBuilder :: new ( )
3711
3756
. with_memory_allocation (
3712
- MemoryAllocation :: try_from ( NumBytes :: from ( WASM_PAGE_SIZE_IN_BYTES * 2 + 100 ) )
3713
- . unwrap ( ) ,
3757
+ MemoryAllocation :: try_from ( NumBytes :: from (
3758
+ WASM_PAGE_SIZE_IN_BYTES * 2 + 100 + canister_history_memory as u64 ,
3759
+ ) )
3760
+ . unwrap ( ) ,
3714
3761
)
3715
3762
. build ( ) ;
3716
3763
0 commit comments