pub(crate) fn install_code(
        &self,
        context: InstallCodeContext,
        state: &mut ReplicatedState,
        instructions_limit: NumInstructions,
        subnet_available_memory: SubnetAvailableMemory,
    ) -> (NumInstructions, Result<NumBytes, CanisterManagerError>) {
        // Copy necessary bits out of the `ReplicatedState`. This is because further
        // below, we take a mutable reference to the old canister state while it
        // is held inside state. Then Rust's borrow checker prevents us from
        // calling further methods on the state.
        let time = state.time();
        let canister_layout_path = state.path().to_path_buf();
        let compute_allocation_used = state.total_compute_allocation();
        let memory_allocation_used = state.total_memory_allocation_used();

        // Perform a battery of validation checks.
        let old_canister = match state.canister_state_mut(&context.canister_id) {
            None => {
                return (
                    instructions_limit,
                    Err(CanisterManagerError::CanisterNotFound(context.canister_id)),
                );
            }
            Some(canister) => canister,
        };
        if let Err(err) = self.validate_compute_allocation(
            compute_allocation_used,
            &old_canister,
            context.compute_allocation,
        ) {
            return (instructions_limit, Err(err));
        }
        if let Err(err) = self.validate_memory_allocation(
            memory_allocation_used,
            &old_canister,
            context.memory_allocation,
        ) {
            return (instructions_limit, Err(err));
        }
        if old_canister.system_state.controller != context.sender {
            return (
                instructions_limit,
                Err(CanisterManagerError::CanisterInvalidController {
                    canister_id: context.canister_id,
                    controller_expected: old_canister.system_state.controller,
                    controller_provided: context.sender,
                }),
            );
        }
        match context.mode {
            CanisterInstallMode::Install => {
                if !canister_is_empty(old_canister) {
                    return (
                        instructions_limit,
                        Err(CanisterManagerError::CanisterNonEmpty(context.canister_id)),
                    );
                }
            }
            CanisterInstallMode::Reinstall | CanisterInstallMode::Upgrade => {}
        }

        // All validation checks have passed. Reserve cycles on the old canister
        // for executing the various hooks such as `start`, `pre_upgrade`,
        // `post_upgrade`.
        let memory_usage = old_canister.memory_usage();
        let compute_allocation = old_canister.scheduler_state.compute_allocation;
        if let Err(err) = self.cycles_account_manager.withdraw_execution_cycles(
            &mut old_canister.system_state,
            memory_usage,
            compute_allocation,
            instructions_limit,
        ) {
            return (instructions_limit, Err((context.canister_id, err).into()));
        }

        // Copy bits out of context as the calls below are going to consume it.
        let canister_id = context.canister_id;
        let mode = context.mode;

        let (instructions_left, result) = match context.mode {
            CanisterInstallMode::Install | CanisterInstallMode::Reinstall => self.install(
                context,
                old_canister,
                instructions_limit,
                subnet_available_memory,
                time,
                canister_layout_path,
            ),
            CanisterInstallMode::Upgrade => self.upgrade(
                context,
                old_canister,
                instructions_limit,
                subnet_available_memory,
                time,
                canister_layout_path,
            ),
        };

        let result = match result {
            Ok((heap_delta, mut new_canister)) => {
                // Refund the left over execution cycles to the new canister and
                // replace the old canister with the new one.

                self.cycles_account_manager
                    .refund_execution_cycles(&mut new_canister.system_state, instructions_left);
                state.put_canister_state(new_canister);
                // We managed to create a new canister and will be dropping the
                // older one. So we get rid of the previous heap to make sure it
                // doesn't interfere with the new deltas and replace the old
                // canister with the new one.
                truncate_canister_heap(&self.log, state.path(), canister_id);
                if mode != CanisterInstallMode::Upgrade {
                    truncate_canister_stable_memory(&self.log, state.path(), canister_id);
                }
                Ok(heap_delta)
            }
            Err(err) => {
                // the install / upgrade failed. Refund the left over cycles to
                // the old canister and leave it in the state.

                self.cycles_account_manager
                    .refund_execution_cycles(&mut old_canister.system_state, instructions_left);
                Err(err)
            }
        };
        (instructions_left, result)
    }
/// Installs code to a canister.
///
/// Only the controller of the canister can install code.
///
/// There are three modes of installation that are supported:
///
/// 1. `CanisterInstallMode::Install`
///    Used for installing code on an empty canister.
///
/// 2. `CanisterInstallMode::Reinstall`
///    Used for installing code on a _non-empty_ canister. All existing
///    state in the canister is cleared.
///
/// 3. `CanisterInstallMode::Upgrade`
///    Used for upgrading a canister while providing a mechanism to
///    preserve its state.
///
/// This function is atomic. In case an error is thrown, the state is
/// unmodified.
Installs code to a canister.
Only the controller of the canister can install code.

There are three modes of installation that are supported.

1. `CanisterInstallMode::Install`
Used for installing code on an empty canister.

2. `CanisterInstallMode::Reinstall`
Used for installing code on a _non-empty_ canister. All existing
state in the canister is cleared.

3. `CanisterInstallMode::Upgrade`
Used for upgrading a canister while providing a mechanism to
preserve its state.

This function is atomic. In case an error is thrown, the state is
unmodified.
Installs code to a canister . Only the controller of the canister can install code . There are three modes of installation that are supported . 1 . ` CanisterInstallMode :: Install ` Used for installing code on an empty canister . 2 . ` CanisterInstallMode :: Reinstall ` Used for installing code on a _non - empty_ canister . All existing state in the canister is cleared . 3 . ` CanisterInstallMode :: Upgrade ` Used for upgrading a canister while providing a mechanism to preserve its state . This function is atomic . In case an error is thrown the state is unmodified .
pub(crate) fn install_code(
        &self,
        context: InstallCodeContext,
        state: &mut ReplicatedState,
        instructions_limit: NumInstructions,
        subnet_available_memory: SubnetAvailableMemory,
    ) -> (NumInstructions, Result<NumBytes, CanisterManagerError>) {
        // Copy necessary bits out of the `ReplicatedState`. This is because further
        // below, we take a mutable reference to the old canister state while it
        // is held inside state. Then Rust's borrow checker prevents us from
        // calling further methods on the state.
        let time = state.time();
        let canister_layout_path = state.path().to_path_buf();
        let compute_allocation_used = state.total_compute_allocation();
        let memory_allocation_used = state.total_memory_allocation_used();
        // Perform a battery of validation checks.
        let old_canister = match state.canister_state_mut(&context.canister_id) {
            None => {
                return (
                    instructions_limit,
                    Err(CanisterManagerError::CanisterNotFound(context.canister_id)),
                );
            }
            Some(canister) => canister,
        };
        if let Err(err) = self.validate_compute_allocation(
            compute_allocation_used,
            &old_canister,
            context.compute_allocation,
        ) {
            return (instructions_limit, Err(err));
        }
        if let Err(err) = self.validate_memory_allocation(
            memory_allocation_used,
            &old_canister,
            context.memory_allocation,
        ) {
            return (instructions_limit, Err(err));
        }
        if old_canister.system_state.controller != context.sender {
            return (
                instructions_limit,
                Err(CanisterManagerError::CanisterInvalidController {
                    canister_id: context.canister_id,
                    controller_expected: old_canister.system_state.controller,
                    controller_provided: context.sender,
                }),
            );
        }
        match context.mode {
            CanisterInstallMode::Install => {
                if !canister_is_empty(old_canister) {
                    return (
                        instructions_limit,
                        Err(CanisterManagerError::CanisterNonEmpty(context.canister_id)),
                    );
                }
            }
            CanisterInstallMode::Reinstall | CanisterInstallMode::Upgrade => {}
        }
        // All validation checks have passed. Reserve cycles on the old canister
        // for executing the various hooks such as `start`, `pre_upgrade`,
        // `post_upgrade`.
        let memory_usage = old_canister.memory_usage();
        let compute_allocation = old_canister.scheduler_state.compute_allocation;
        if let Err(err) = self.cycles_account_manager.withdraw_execution_cycles(
            &mut old_canister.system_state,
            memory_usage,
            compute_allocation,
            instructions_limit,
        ) {
            return (instructions_limit, Err((context.canister_id, err).into()));
        }
        // Copy bits out of context as the calls below are going to consume it.
        let canister_id = context.canister_id;
        let mode = context.mode;
        let (instructions_left, result) = match context.mode {
            CanisterInstallMode::Install | CanisterInstallMode::Reinstall => self.install(
                context,
                old_canister,
                instructions_limit,
                subnet_available_memory,
                time,
                canister_layout_path,
            ),
            CanisterInstallMode::Upgrade => self.upgrade(
                context,
                old_canister,
                instructions_limit,
                subnet_available_memory,
                time,
                canister_layout_path,
            ),
        };
        let result = match result {
            Ok((heap_delta, mut new_canister)) => {
                // Refund the left over execution cycles to the new canister and
                // replace the old canister with the new one.
                self.cycles_account_manager
                    .refund_execution_cycles(&mut new_canister.system_state, instructions_left);
                state.put_canister_state(new_canister);
                // We managed to create a new canister and will be dropping the
                // older one. So we get rid of the previous heap to make sure it
                // doesn't interfere with the new deltas and replace the old
                // canister with the new one.
                truncate_canister_heap(&self.log, state.path(), canister_id);
                if mode != CanisterInstallMode::Upgrade {
                    truncate_canister_stable_memory(&self.log, state.path(), canister_id);
                }
                Ok(heap_delta)
            }
            Err(err) => {
                // the install / upgrade failed. Refund the left over cycles to
                // the old canister and leave it in the state.
                self.cycles_account_manager
                    .refund_execution_cycles(&mut old_canister.system_state, instructions_left);
                Err(err)
            }
        };
        (instructions_left, result)
    }
pub ( crate ) fn install_code ( & self , context : InstallCodeContext , state : & mut ReplicatedState , instructions_limit : NumInstructions , subnet_available_memory : SubnetAvailableMemory , ) -> ( NumInstructions , Result < NumBytes , CanisterManagerError > ) { // Copy necessary bits out of the `ReplicatedState`. This is because further // below, we take a mutable reference to the old canister state while it // is held inside state. Then Rust's borrow checker prevents us from // calling further methods on the state. let time = state . time ( ) ; let canister_layout_path = state . path ( ) . to_path_buf ( ) ; let compute_allocation_used = state . total_compute_allocation ( ) ; let memory_allocation_used = state . total_memory_allocation_used ( ) ; // Perform a battery of validation checks. let old_canister = match state . canister_state_mut ( & context . canister_id ) { None => { return ( instructions_limit , Err ( CanisterManagerError :: CanisterNotFound ( context . canister_id ) ) , ) ; } Some ( canister ) => canister , } ; if let Err ( err ) = self . validate_compute_allocation ( compute_allocation_used , & old_canister , context . compute_allocation , ) { return ( instructions_limit , Err ( err ) ) ; } if let Err ( err ) = self . validate_memory_allocation ( memory_allocation_used , & old_canister , context . memory_allocation , ) { return ( instructions_limit , Err ( err ) ) ; } if old_canister . system_state . controller != context . sender { return ( instructions_limit , Err ( CanisterManagerError :: CanisterInvalidController { canister_id : context . canister_id , controller_expected : old_canister . system_state . controller , controller_provided : context . sender , } ) , ) ; } match context . mode { CanisterInstallMode :: Install => { if ! canister_is_empty ( old_canister ) { return ( instructions_limit , Err ( CanisterManagerError :: CanisterNonEmpty ( context . canister_id ) ) , ) ; } } CanisterInstallMode :: Reinstall | CanisterInstallMode :: Upgrade => { } } // All validation checks have passed. Reserve cycles on the old canister // for executing the various hooks such as `start`, `pre_upgrade`, // `post_upgrade`. let memory_usage = old_canister . memory_usage ( ) ; let compute_allocation = old_canister . scheduler_state . compute_allocation ; if let Err ( err ) = self . cycles_account_manager . withdraw_execution_cycles ( & mut old_canister . system_state , memory_usage , compute_allocation , instructions_limit , ) { return ( instructions_limit , Err ( ( context . canister_id , err ) . into ( ) ) ) ; } // Copy bits out of context as the calls below are going to consume it. let canister_id = context . canister_id ; let mode = context . mode ; let ( instructions_left , result ) = match context . mode { CanisterInstallMode :: Install | CanisterInstallMode :: Reinstall => self . install ( context , old_canister , instructions_limit , subnet_available_memory , time , canister_layout_path , ) , CanisterInstallMode :: Upgrade => self . upgrade ( context , old_canister , instructions_limit , subnet_available_memory , time , canister_layout_path , ) , } ; let result = match result { Ok ( ( heap_delta , mut new_canister ) ) => { // Refund the left over execution cycles to the new canister and // replace the old canister with the new one. self . cycles_account_manager . refund_execution_cycles ( & mut new_canister . system_state , instructions_left ) ; state . put_canister_state ( new_canister ) ; // We managed to create a new canister and will be dropping the // older one. So we get rid of the previous heap to make sure it // doesn't interfere with the new deltas and replace the old // canister with the new one. truncate_canister_heap ( & self . log , state . path ( ) , canister_id ) ; if mode != CanisterInstallMode :: Upgrade { truncate_canister_stable_memory ( & self . log , state . path ( ) , canister_id ) ; } Ok ( heap_delta ) } Err ( err ) => { // the install / upgrade failed. Refund the left over cycles to // the old canister and leave it in the state. self . cycles_account_manager . refund_execution_cycles ( & mut old_canister . system_state , instructions_left ) ; Err ( err ) } } ; ( instructions_left , result ) }
Installs code to a canister.
Installs code to a canister .
&self
context
InstallCodeContext
state
&mut ReplicatedState
instructions_limit
NumInstructions
subnet_available_memory
SubnetAvailableMemory
&self
context
InstallCodeContext
state
&mut ReplicatedState
instructions_limit
NumInstructions
subnet_available_memory
SubnetAvailableMemory