Skip to content

refactor: install the canister memories in create_execution_state - #11142

Open
mraszyk wants to merge 3 commits into
masterfrom
mraszyk/create-execution-state-memory-source
Open

refactor: install the canister memories in create_execution_state#11142
mraszyk wants to merge 3 commits into
masterfrom
mraszyk/create-execution-state-memory-source

Conversation

@mraszyk

@mraszyk mraszyk commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Hypervisor::create_execution_state always built the initial memories of the new Wasm module, and every caller then overwrote them afterwards: install_code swapped in the preserved memories in InstallCodeHelper::replace_execution_state_and_allocations, and load_canister_snapshot assigned the snapshot's memories directly. Which memories a new execution state ends up with was hence decided in three different places.

Make create_execution_state take a mandatory MemorySource describing where the memories come from (Fresh for install/reinstall, Preserve for upgrades, Explicit for snapshot restore) and apply it there, so it is the single place that assembles an execution state's memories.

The wasm_memory_persistence upgrade option only ever selected the main memory handling based on the install mode; the two enhanced orthogonal persistence checks in determine_main_memory_handling merely rejected otherwise valid combinations. Split it accordingly into the infallible main_memory_handling, which runs before the execution state is created, and validate_wasm_memory_persistence, which runs after it in the same position relative to the compilation charge as before.

load_canister_snapshot now builds the memories to restore before prepaying for the message. As a result a failure to load them (CanisterSnapshotNotLoadable) no longer charges the canister for compiling the snapshot's module and now takes precedence over NotEnoughCycles.

`Hypervisor::create_execution_state` always built the initial memories of
the new Wasm module, and every caller then overwrote them afterwards:
`install_code` swapped in the preserved memories in
`InstallCodeHelper::replace_execution_state_and_allocations`, and
`load_canister_snapshot` assigned the snapshot's memories directly. Which
memories a new execution state ends up with was hence decided in three
different places, none of which the type system forced a caller to visit.

Make `create_execution_state` take a mandatory `MemorySource` describing
where the memories come from (`Fresh` for install/reinstall, `Preserve`
for upgrades, `Explicit` for snapshot restore) and apply it there, so it
is the single place that assembles an execution state's memories.

The `wasm_memory_persistence` upgrade option only ever selected the main
memory handling based on the install mode; the two enhanced orthogonal
persistence checks in `determine_main_memory_handling` merely rejected
otherwise valid combinations. Split it accordingly into the infallible
`main_memory_handling`, which runs before the execution state is created,
and `validate_wasm_memory_persistence`, which runs after it in the same
position relative to the compilation charge as before.

`load_canister_snapshot` now builds the memories to restore before
prepaying for the message. As a result a failure to load them
(`CanisterSnapshotNotLoadable`) no longer charges the canister for
compiling the snapshot's module and now takes precedence over
`NotEnoughCycles`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mraszyk and others added 2 commits August 14, 2026 12:23
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Centralizes execution-state memory selection in Hypervisor::create_execution_state.

Changes:

  • Adds fresh, preserved, and explicit memory sources.
  • Simplifies install/upgrade memory handling and persistence validation.
  • Prepares snapshot memories before cycle prepayment.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/lib.rs Re-exports memory-handling APIs.
src/hypervisor.rs Applies memory sources during state creation.
src/execution/upgrade/tests.rs Updates stage documentation.
src/execution/upgrade.rs Preserves upgrade memories and separates validation.
src/execution/install.rs Uses fresh memories for installs.
src/execution/install_code.rs Removes post-creation memory swapping.
src/canister_manager.rs Prepares snapshot memories before charging.
benches/management_canister/create_execution_state.rs Updates benchmark invocation.
benches/lib/src/common.rs Updates benchmark helper invocation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rs/execution_environment/src/canister_manager.rs
Comment on lines +148 to +155
/// Specifies the handling of the canister's memories.
/// * On install and re-install:
/// - Replace both the stable memory and the main memory.
/// * On upgrade:
/// - For canisters with enhanced orthogonal persistence (Motoko):
/// Retain both the main memory and the stable memory.
/// - For all other canisters:
/// Retain only the stable memory and erase the main memory.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this one, the current formulation is indeed a bit imprecise (informal), but describes the intent (Motoko EOP).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you could reorder things as suggested, but retaining your existing structure:

Suggested change
/// Specifies the handling of the canister's memories.
/// * On install and re-install:
/// - Replace both the stable memory and the main memory.
/// * On upgrade:
/// - For canisters with enhanced orthogonal persistence (Motoko):
/// Retain both the main memory and the stable memory.
/// - For all other canisters:
/// Retain only the stable memory and erase the main memory.
/// Specifies the handling of the canister's memories.
/// * On install and re-install:
/// - Replace both the stable memory and the main memory.
/// * On upgrade:
/// - Stable memory: retained for all canisters.
/// - Main memory: retained for canisters with enhanced orthogonal persistence
/// (Motoko) when the validated persistence option is `Keep`; and erased in
/// all other cases.

Or you can stick with what you have. No strong opinion.

@mraszyk
mraszyk marked this pull request as ready for review August 14, 2026 13:48
@mraszyk
mraszyk requested a review from a team as a code owner August 14, 2026 13:48
@zeropath-ai

zeropath-ai Bot commented Aug 14, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 082f70c.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► rs/execution_environment/benches/lib/src/common.rs
• Add MemorySource::Fresh to ExecutionEnvironment create call
► rs/execution_environment/benches/management_canister/create_execution_state.rs
• Import MemorySource
• Pass MemorySource::Fresh to create_execution_state
Enhancement ► rs/execution_environment/src/canister_manager.rs
• Import MemorySource from hypervisor
• Build up snapshot memories up front for upgrade path (snapshot_wasm_memory, snapshot_stable_memory) and pass to create_execution_state via MemorySource::Explicit
Enhancement ► rs/execution_environment/src/execution/install.rs
• Use MemorySource::Fresh when calling create_execution_state during install path
Enhancement ► rs/execution_environment/src/execution/install_code.rs
• Remove MemoryHandling related struct usage in replace_execution_state_and_allocations signature and callsites (simplify to not pass memory_handling)
Enhancement ► rs/execution_environment/src/execution/upgrade.rs
• Add MemorySource and MemoryHandling related imports
• Introduce construction of new_memories via MemorySource::Preserve or MemorySource::Fresh for upgrade path
• Replace direct memory handling logic with memory source flow and validation call
• Remove direct MemoryHandling usage in upgrade path
Enhancement ► rs/execution_environment/src/execution/upgrade/tests.rs
• Update test comments to reflect new validation flow and memory persistence checks
Enhancement ► rs/execution_environment/src/hypervisor.rs
• Introduce MemoryHandling enum, CanisterMemoryHandling struct, and MemorySource enum to describe memory sourcing/persistence strategies (Fresh, Preserve, Explicit)
Enhancement ► rs/execution_environment/src/hypervisor.rs (MemorySource usage and handling in create_execution_state)
• Extend Hypervisor::create_execution_state to apply MemorySource variants (Fresh, Preserve, Explicit) to execution state's memories
Enhancement ► rs/execution_environment/src/lib.rs
• Re-export MemoryHandling, MemorySource, CanisterMemoryHandling alongside Hypervisor and others

// is constructed once per operation and consumed right away.
#[allow(clippy::large_enum_variant)]
pub enum MemorySource<'a> {
/// Install and re-install: keep the initial memories of the new module.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Keep" is potentially confusing in this context (particularly given that there's a Preserve variant below, with the exact opposite behavior).

Suggested change
/// Install and re-install: keep the initial memories of the new module.
/// Install and re-install: use the newly installed module's initial memories.

Comment on lines +148 to +155
/// Specifies the handling of the canister's memories.
/// * On install and re-install:
/// - Replace both the stable memory and the main memory.
/// * On upgrade:
/// - For canisters with enhanced orthogonal persistence (Motoko):
/// Retain both the main memory and the stable memory.
/// - For all other canisters:
/// Retain only the stable memory and erase the main memory.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you could reorder things as suggested, but retaining your existing structure:

Suggested change
/// Specifies the handling of the canister's memories.
/// * On install and re-install:
/// - Replace both the stable memory and the main memory.
/// * On upgrade:
/// - For canisters with enhanced orthogonal persistence (Motoko):
/// Retain both the main memory and the stable memory.
/// - For all other canisters:
/// Retain only the stable memory and erase the main memory.
/// Specifies the handling of the canister's memories.
/// * On install and re-install:
/// - Replace both the stable memory and the main memory.
/// * On upgrade:
/// - Stable memory: retained for all canisters.
/// - Main memory: retained for canisters with enhanced orthogonal persistence
/// (Motoko) when the validated persistence option is `Keep`; and erased in
/// all other cases.

Or you can stick with what you have. No strong opinion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants