Internet Computer の鍵となるフィーチャの一つは, キャニスタ・スマート・コントラクトの状態を伝統的なデータベースにではなく, WebAssembly のメモリとグローバルを使って永続化する能力です. つまり, 明示的にユーザが指示しなくても魔法のように, メッセージを受け取る前には状態が復元され, メッセージを処理した後には保存されるのです. 自動的でユーザ透過な (永続的な) 状態は 直交永続性 とも呼ばれています.

One key feature of the Internet Computer is its ability to persist canister smart contract state using WebAssembly memory and globals rather than a traditional database. This means that that the entire state of a canister smart contract is magically restored before, and saved after, each message, without explicit user instruction. This automatic and user-transparent preservation of state is called orthogonal persistence.

直交性属性は便利ではありますが, いざキャニスタ・スマート・コントラクトのコードをアップグレードしようとすると, ある挑戦が待ち構えています. キャニスタ・スマート・コントラクトの状態の明示的な表現がないのに, どうやって任意のアプリケーション・データを古いキャニスタ・スマート・コントラクトから新しいキャニスタ・スマート・コントラクトに移動すれば良いのでしょうか?

Though convenient, orthogonal persistence poses a challenge when it comes to upgrading the code of a canister smart contract. Without an explicit representation of the canister smart contract’s state, how does one tranfer any application data from the retired canister smart contract to its replacement?

データ損失なくアップグレードを取り込むには, キャニスタ・スマート・コントラクトの極めて重要なデータをアップグレードしたキャニスタ・スマート・コントラクトに 移行 するための何らかの新しい仕組みが必要になります. 例えば, あなたがユーザを登録するキャニスタ・スマート・コントラクトの問題点を解決したり, 機能を付け加えるために新しいヴァージョンを配備しようとしたとしましょう. このとき, アップグレードの過程で既存の登録がちゃんと存続することを保証しなければなりません.

Accommodating upgrades without data loss requires some new facility to migrate a canister smart contract’s crucial data to the upgraded canister smart contract. For example, if you want to deploy a new version of a user-registration canister smart contract to fix an issue or add functionality, you need to ensure that existing registrations survive the upgrade process.

Internet Computer の永続化モデルでは, キャニスタ・スマート・コントラクトがそのようなデータを (通常のキャニスタ・スマート・コントラクトのメモリとは別の) 専用の 安定メモリ に保存/読み出しできる, すなわちアップグレードを越えて保存され, キャニスタ・スマート・コントラクトがデータをまとめて新たに置き換えられるキャニスタ・スマート・コントラクトに移動できるようになっています.

The Internet Computer's persistence model allows a canister smart contract to save and restore such data to dedicated stable memory that, unlike ordinary canister smart contract memory, is retained across an upgrade, allowing a canister smart contract to transfer data in bulk to its replacement canister smart contract.

Motoko で記述されたアプリケーションでは, 状態を Internet Computer の安定メモリを利用して保存できるような高レベルのサポートを言語が提供しています.

For applications written in Motoko, the language provides high-level support for preserving state that leverages Internet Computer stable memory. This higher-level feature, called stable storage, is designed to accommodate changes to both the application data and to the Motoko compiler used to produce the application code.

安定メモリを活用し, アップグレード後も残しておきたいデータを見越して, 指定するかどうかは (アプリケーション・プログラマである) あなた次第です. あなたが永続化を決めるデータがアクタの状態の一部なのか, 全部なのか, なくていいのかは, アプリケーションによって異なります.

Utilizing stable storage depends on you — as the application programmer — anticipating and indicating the data you want to retain after an upgrade. Depending on the application, the data you decide to persist might be some, all, or none of a given actor’s state.

Declaring stable variables

アクタの変数を安定ストレージ (Internet Computer の安定メモリ) に入れたいときには, その変数宣言の修飾子に stable キーワードを使います.

In an actor, you can nominate a variable for stable storage (in Internet Computer stable memory) by using the stable keyword as a modifier in the variable’s declaration.

もっと正確に言うと, アクタのすべての let , var 変数宣言では, その変数が stableflexible であるかを指定することができます. 修飾子を付けなければ, その変数はデフォルトで flexible であるということになります.

More precisely, every let and var variable declaration in an actor can specify whether the variable is stable or flexible. If you don’t provide a modifier, the variable is declared as flexible by default.

次の簡単な例題では, カウンタの値をアップグレード中も保存できるような安定カウンタを宣言しています:

The following is a simple example of how to declare a stable counter that can be upgraded while preserving the counter’s value:

actor Counter {

  stable var value = 0;

  public func inc() : async Nat {
    value += 1;
    return value;
  };
}

:::note

stable flexible 修飾子を付けられるのは, アクタのフィールドlet var 宣言のみです. プログラムの他の部分で使うことはできません.

You can only use the stable or flexible modifier on let and var declarations that are actor fields. You cannot use these modifiers anywhere else in your program.

:::

Typing

Because the compiler must ensure that stable variables are both compatible with and meaningful in the replacement program after an upgrade, the following type restrictions apply to stable state:

コンパイラは, 安定変数がアップグレード後も新しいプログラムと互換性があり, 有意味であることを保証しなければなりません. そのために安定状態には以下の型制約が課せられます.

ここで, ある型が stable であるとは, その型の中のすべての var 修飾子を無視したときに shared になることです.

where a type is stable if the type obtained by ignoring any var modifiers within it is shared.

したがって, 安定型と共有型の違いは, 安定型では可変性をサポートしていることになります. 共有型と同様, 安定型は (ローカル関数とローカル関数から構成される構造 (オブジェクトなど) を除いて) 一級データに限定されます. 関数を除外する必要があるのは, (データとコードから成る) 関数値の意味をアップグレードを跨いで保存するのは簡単なことではないからです (単なるデータの意味を保存するのは (可変であれ不変であれ) 可能なのですが).

Thus the only difference between stable types and shared types is the former’s support for mutation. Like shared types, stable types are restricted to first-order data, excluding local functions and structures built from local functions (such as objects). This exclusion of functions is required because the meaning of a function value — consisting of both data and code — cannot easily be preserved across an upgrade, while the meaning of plain data — mutable or not — can be.