pub(crate) fn install_code(
        &self,
        context: InstallCodeContext,
        state: &mut ReplicatedState,
        mut execution_parameters: ExecutionParameters,
    ) -> (
        NumInstructions,
        Result<InstallCodeResult, 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_taken = state.total_memory_taken();

        // Perform a battery of validation checks.
        let old_canister = match state.canister_state_mut(&context.canister_id) {
            None => {
                return (
                    execution_parameters.instruction_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 (execution_parameters.instruction_limit, Err(err));
        }
        if let Err(err) =
            self.validate_memory_allocation(memory_taken, old_canister, context.memory_allocation)
        {
            return (execution_parameters.instruction_limit, Err(err));
        }
        if let Err(err) = self.validate_controller(old_canister, &context.sender) {
            return (execution_parameters.instruction_limit, Err(err));
        }
        match context.mode {
            CanisterInstallMode::Install => {
                if old_canister.execution_state.is_some() {
                    return (
                        execution_parameters.instruction_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(self.config.own_subnet_type);
        let compute_allocation = old_canister.scheduler_state.compute_allocation;
        if let MemoryAllocation::Reserved(bytes) = old_canister.memory_allocation() {
            execution_parameters.canister_memory_limit = bytes;
        }
        execution_parameters.compute_allocation = compute_allocation;

        if let Err(err) = self.cycles_account_manager.withdraw_execution_cycles(
            &mut old_canister.system_state,
            memory_usage,
            compute_allocation,
            execution_parameters.instruction_limit,
        ) {
            return (
                execution_parameters.instruction_limit,
                Err(CanisterManagerError::InstallCodeNotEnoughCycles(err)),
            );
        }

        // 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,
                time,
                canister_layout_path,
                execution_parameters,
            ),
            CanisterInstallMode::Upgrade => self.upgrade(
                context,
                old_canister,
                time,
                canister_layout_path,
                execution_parameters,
            ),
        };

        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.

                let old_wasm_hash = self.get_wasm_hash(old_canister);
                let new_wasm_hash = self.get_wasm_hash(&new_canister);
                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(InstallCodeResult {
                    heap_delta,
                    old_wasm_hash,
                    new_wasm_hash,
                })
            }
            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,
        mut execution_parameters: ExecutionParameters,
    ) -> (
        NumInstructions,
        Result<InstallCodeResult, 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_taken = state.total_memory_taken();
        // Perform a battery of validation checks.
        let old_canister = match state.canister_state_mut(&context.canister_id) {
            None => {
                return (
                    execution_parameters.instruction_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 (execution_parameters.instruction_limit, Err(err));
        }
        if let Err(err) =
            self.validate_memory_allocation(memory_taken, old_canister, context.memory_allocation)
        {
            return (execution_parameters.instruction_limit, Err(err));
        }
        if let Err(err) = self.validate_controller(old_canister, &context.sender) {
            return (execution_parameters.instruction_limit, Err(err));
        }
        match context.mode {
            CanisterInstallMode::Install => {
                if old_canister.execution_state.is_some() {
                    return (
                        execution_parameters.instruction_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(self.config.own_subnet_type);
        let compute_allocation = old_canister.scheduler_state.compute_allocation;
        if let MemoryAllocation::Reserved(bytes) = old_canister.memory_allocation() {
            execution_parameters.canister_memory_limit = bytes;
        }
        execution_parameters.compute_allocation = compute_allocation;
        if let Err(err) = self.cycles_account_manager.withdraw_execution_cycles(
            &mut old_canister.system_state,
            memory_usage,
            compute_allocation,
            execution_parameters.instruction_limit,
        ) {
            return (
                execution_parameters.instruction_limit,
                Err(CanisterManagerError::InstallCodeNotEnoughCycles(err)),
            );
        }
        // 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,
                time,
                canister_layout_path,
                execution_parameters,
            ),
            CanisterInstallMode::Upgrade => self.upgrade(
                context,
                old_canister,
                time,
                canister_layout_path,
                execution_parameters,
            ),
        };
        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.
                let old_wasm_hash = self.get_wasm_hash(old_canister);
                let new_wasm_hash = self.get_wasm_hash(&new_canister);
                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(InstallCodeResult {
                    heap_delta,
                    old_wasm_hash,
                    new_wasm_hash,
                })
            }
            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 , mut execution_parameters : ExecutionParameters , ) -> ( NumInstructions , Result < InstallCodeResult , 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_taken = state . total_memory_taken ( ) ; // Perform a battery of validation checks. let old_canister = match state . canister_state_mut ( & context . canister_id ) { None => { return ( execution_parameters . instruction_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 ( execution_parameters . instruction_limit , Err ( err ) ) ; } if let Err ( err ) = self . validate_memory_allocation ( memory_taken , old_canister , context . memory_allocation ) { return ( execution_parameters . instruction_limit , Err ( err ) ) ; } if let Err ( err ) = self . validate_controller ( old_canister , & context . sender ) { return ( execution_parameters . instruction_limit , Err ( err ) ) ; } match context . mode { CanisterInstallMode :: Install => { if old_canister . execution_state . is_some ( ) { return ( execution_parameters . instruction_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 ( self . config . own_subnet_type ) ; let compute_allocation = old_canister . scheduler_state . compute_allocation ; if let MemoryAllocation :: Reserved ( bytes ) = old_canister . memory_allocation ( ) { execution_parameters . canister_memory_limit = bytes ; } execution_parameters . compute_allocation = compute_allocation ; if let Err ( err ) = self . cycles_account_manager . withdraw_execution_cycles ( & mut old_canister . system_state , memory_usage , compute_allocation , execution_parameters . instruction_limit , ) { return ( execution_parameters . instruction_limit , Err ( CanisterManagerError :: InstallCodeNotEnoughCycles ( err ) ) , ) ; } // 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 , time , canister_layout_path , execution_parameters , ) , CanisterInstallMode :: Upgrade => self . upgrade ( context , old_canister , time , canister_layout_path , execution_parameters , ) , } ; 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. let old_wasm_hash = self . get_wasm_hash ( old_canister ) ; let new_wasm_hash = self . get_wasm_hash ( & new_canister ) ; 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 ( InstallCodeResult { heap_delta , old_wasm_hash , new_wasm_hash , } ) } 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
execution_parameters
ExecutionParameters
&self
context
InstallCodeContext
state
&mut ReplicatedState
execution_parameters
ExecutionParameters