Move は、2018 年の Libra プロジェクトの初期段階で誕生しました。Mysten の 2 人の創設者 (Evan と私) は、Libra の創設チームでもありました。新しい言語を作成することを決定する前に、初期のLibraチームは既存のスマートコントラクトのユースケースと言語を集中的に研究して、開発者が何をしたいのか、既存の言語ではどこが機能していないのかを理解しました。私たちが発見した重要な問題は、スマート コントラクトはすべて資産とアクセス制御に関するものであるにもかかわらず、初期のスマート コントラクト言語にはその両方の型と値の表現が欠けていたということです。私たちの仮説は、これらの重要な概念に最上級の抽象化を提供すれば、スマート コントラクトのセキュリティとスマート コントラクト プログラマの生産性を大幅に向上できるというものです。目前のタスクに適切な語彙を持っていることが大きな違いを生みます。長年にわたり、多くの人々が Move の設計と実装に貢献してきました。この言語は、「Web3 の JavaScript」になるという大胆な目標を掲げ、主要なアイデアからプラットフォームに依存しないスマート コントラクト言語へと進化しました。
本日、Move とSui の統合におけるマイルストーンを発表できることを嬉しく思います。 Sui Move の機能は完全で、高度なツールによってサポートされており、次のセクションを含む広範なドキュメントと例が含まれています。
Sui Move オブジェクトを使用したプログラミングに関する一連のチュートリアル。Sui Move の基本的な知識、設計パターン、サンプルに関する開発ドキュメント。Mysten Move チームが開発した、コード分析とエラー診断をサポートする VSCode 拡張プラグイン。 Move の構築、テスト、パッケージ管理、ドキュメント生成、および sui CLI と統合された Move バリデータ。
Move のユニークな点
Move は、クロスプラットフォームの組み込み言語です。コア構文自体は非常に単純です。構造体、整数、アドレスなどの一般的な概念はありますが、アカウントやトランザクション、時間、暗号化などのブロックチェーン固有の概念はありません。これらの機能は、Move と統合されたブロックチェーン プラットフォームによって提供される必要があります。重要なのは、これらのブロックチェーンは独自の Move フォークを必要としないことです。各プラットフォームは同じ Move 仮想マシン、バイトコード バリデーター、コンパイラー、バリデーター、パッケージ マネージャー、および CLI を使用しますが、これらのコア コンポーネントの上にコードを構築することで、ブロックチェーン固有の機能を追加します。 。 Diem は Move を組み込んだ最初のブロックチェーンであり、その後の Move ベースのブロックチェーン (0L、StarCoin、Aptos を含む) のほとんどは Diem スタイルのアプローチを採用しました。 Diem スタイルの Move にはいくつかの優れた利点がありますが、Diem の許可型の性質と Diem ブロックチェーンの特定の実装詳細 (特にストレージ モデル) の両方により、一部の基本的なスマート コントラクトのユースケースの実装が困難になります。特に、Move と Diem の元の設計は NFT の人気が爆発的に高まるより前のものであり、NFT 関連のユースケースの実装を特に困難にするいくつかの癖があります。この投稿では、3 つの例を通じてオリジナルの Diem スタイルの Move 埋め込みの問題を示し、Sui Move でこの問題をどのように解決したかについて説明します。 Move についてはある程度の基本を理解していることを前提としていますが、これらの重要なポイントがプログラミングの背景を持つ人であれば誰でも理解できることを願っています。
大規模なアセット作成時のスムーズなエクスペリエンス
アセットを一括で作成および配布できる機能は、Web3 ユーザーのオンボーディングとエンゲージメントの両方にとって重要です。おそらく、Twitchストリーマーは記念NFTを配布したい、クリエイターは特別なイベントのチケットを送りたい、またはゲーム開発者はすべてのプレイヤーに新しいアイテムをエアドロップしたいと考えています。これは、Diem スタイルの Move でアセットを大量に鋳造するためのコードを作成する (失敗した) 試みです。このコードは、受信者アドレスのベクトルを入力として受け取り、受信者ごとにアセットを生成し、アセットの転送を試みます。
Diem スタイルの移動では、グローバル ストレージは (アドレス、タイプ名) ペアによって型付けされます。つまり、各アドレスは特定の型の資産を最大 1 つ保存できます。したがって、 move_to(receiverient, CoolAsset { ...} は、CoolAsset を受信者のアドレスに格納して移動しようとします。ただし、このコードは、move_to(receiverient, ...) 行でコンパイルに失敗します。重要な問題は、 です。 Diem スタイルの Move では、トランザクションが A 以外のアドレスから送信され、A で作成されたアカウントの所有者がトランザクションを送信して CoolAsset を受信することを明示的に選択しない限り、CoolAsset タイプの値をアドレス A に送信することはできません。これらは、アセットを受け取るための 2 つのトランザクションです。これを行う決定は、アカウントの作成を慎重に制限し、ストレージ システムによってアカウントが制限されるのを防ぐ必要がある許可システムである Diem にとっては理にかなっています。ただし、あまりにも多くの資産を保持するのではなく、オンボーディングメカニズムとして資産割り当てを使用するか、イーサリアムや同様のブロックチェーンのように一般にユーザー間で資産が自由に流れることを許可するオープンシステムの場合、それは非常に制限されています。 。
同じ機能をSui Moveで実装するコードは次のとおりです。
Sui Move のグローバル ストレージはオブジェクト ID によってキー化されます。キーと値のペアを持つすべての構造は「Sui オブジェクト」であり、グローバルに一意の ID フィールドが必要です。 Sui Move は、制限的な move_to 構造体を使用する代わりに、任意の Sui オブジェクトで使用できる転送プリミティブを導入します。内部では、このプリミティブは ID をグローバル ストレージ内の CoolAsset にマップし、値が受信者によって所有されていることを示すメタデータを追加します。 Swiss バージョンの Mass_mint の興味深い特性は、他のすべてのトランザクション (mass_mint を呼び出す他のトランザクションも含む) と交換されることです。 Sui ランタイムはこれに気づき、コンセンサスを必要としないビザンチン コンセンサス ブロードキャスト「高速パス」を介して、この関数を呼び出すトランザクションを送信します。このようなトランザクションは、コミットまたは並行して実行できます。これにはプログラマ側の努力は必要ありません (プログラマは上記のコードを書くだけで、残りはランタイムが処理します)。おそらく微妙ですが、このコードの Diem バリアントではこれは当てはまりません。たとえ上記のコードが機能しても、存在します。 guid::create 呼び出しは、GUID を生成したりアカウント リソースにアクセスしたりする他のトランザクションとの競合点を作成します。場合によっては、引数を回避するために Diem スタイルの Move コードを書き直すことが可能ですが、従来の Diem スタイル Move の記述方法の多くでは、並列実行を妨げる小さな障害が発生します。
ローカル資産の所有権と移転
実際にコンパイルして実行する回避策を使用して、Diem スタイルの Move コードを拡張してみましょう。これを行う通常の方法は「ラッパー パターン」です。ボブは CoolAsset をアリスのアドレスに直接移動できないため、Alice に CoolAsset を受け取るために「オプトイン」するよう依頼し、最初に Collection タイプを含むラッパー タイプ CoolAssetStore を公開します。 (テーブル)。アリスは、opt_in 関数を呼び出すことでこれを行うことができます。次に、ボブが CoolAssetStore から Alice の CoolAssetStore に CoolAsset を移動できるようにするコードを追加します。このコードでは、さらに手間を加えてみましょう。CoolAsset の転送は、少なくとも 30 日前に作成された場合にのみ許可されます。この種のポリシーは、(たとえば)投機家がイベント チケットを購入したり宣伝したりするのを阻止して、本物のファンが手頃な価格でチケットを入手しやすくしたいと考えているクリエイターにとって重要です。
このコードは有効です。しかし、これは、アリスからボブに資産を転送するタスクを実行するかなり複雑な方法です。スイムーブの別の実装を見てみましょう
このコードははるかに短いです。ここで注意すべき重要な点は、cool_transfer はエントリ関数 (つまり、Sui ランタイムによってトランザクションを通じて直接呼び出すことができる) ですが、入力として CoolAsset 型のパラメーターがあるということです。これもまた、Sui Runtime の魔法です。トランザクションには、操作対象の一連のオブジェクト ID が含まれており、Sui Runtime は次のことを行います。
ID をオブジェクト値に解析します (上記の Diem スタイル コードのborrow_global_mut および table_remove 部分は必要ありません)。 オブジェクトがトランザクションの送信者によって所有されているかどうかを確認します (signer::address_of セクションと上記の関連コードが不要になります)。この部分は特に興味深いので、すぐに説明します。Sui では、安全なオブジェクトの所有権のチェックはランタイムの一部です。呼び出された関数のパラメーターの型に従ってオブジェクトの値の型を確認し、オブジェクトの値とその他のパラメーターをバインドします。パラメータをcool_transferし、関数を呼び出します。
これにより、Sui Move のプログラマーは、ロジックの「引き出し」部分のテンプレートをスキップして、楽しい部分、つまり 30 日間の有効期限ポリシーのチェックに直接ジャンプできるようになりました。同様に、「入金」の部分も、上で説明したSui Moveの転送構造により大幅に簡素化されています。最後に、CoolAssetStore のような内部コレクションを備えたラッパー型を導入する必要はありません。ID インデックス付きの Sui グローバル ストアを使用すると、1 つのアドレスに特定の型の任意の数の値を格納できます。指摘すべきもう 1 つの違いは、Diem スタイルの Cool_transfer には 5 つの中止方法がある (つまり、失敗して転送を完了せずにユーザーにガス料金を請求する) のに対し、Sui Move Cool_transfer には中止する方法が 1 つしかない (30 日ポリシーに違反した場合) ことです。オブジェクトの所有権チェックをランタイムにオフロードすることは、人間工学の観点だけでなく、セキュリティの観点からも大きなメリットとなります。実行時レベルで安全性を実装すると、構成要素にこれらのチェックを実装する際のエラー (または完全に忘れてしまうこと) が防止されます。最後に、Sui Move のエントリ ポイント関数シグネチャ Cool_transfer(asset: CoolAsset, ...) は、この関数が何を行うかについて多くの情報を提供することに注意してください (これは、Diem スタイルの関数シグネチャよりも不透明です)。この関数は CoolAsset を転送する許可を要求しており、別の関数 f(asset: &mut CoolAsset, ...) は CoolAsset を書き込む (ただし転送はしない) 許可を要求し、g(asset: &CoolAsset, ..) を要求していると考えることができます。読み取り許可を求めているだけです。
この情報は関数シグネチャで直接利用できるため (実行や静的分析は必要ありません!)、ウォレットやその他のクライアント ツールで直接使用できます。 Sui Wallet では、これらの構造化された関数署名を活用して、iOS/Android スタイルの許可プロンプトをユーザーに提供する、人間が判読できる署名リクエストに取り組んでいます。ウォレットは、「このトランザクションには、CoolAsset の読み取り、AssetCollection への書き込み、ConcertTicket の転送の許可が必要です。続行しますか?」のようなメッセージを送信できます。
人間が判読できる署名リクエストは、ウォレットユーザーが与える影響を理解せずにやみくもにトランザクションに署名する必要がある、Diem スタイルの Move! を使用するプラットフォームを含む、多くの既存のプラットフォームに存在する大規模な攻撃ベクトルを解決します。私たちは、ウォレット体験のリスクを軽減することが、暗号通貨ウォレットの主流採用を促進する上で重要なステップであると信じており、人間が判読できる署名リクエストなどの機能を有効にすることでこの目標をサポートするように、Sui Move を設計しました。
さまざまなアセットをバンドルする
最後に、さまざまな種類のアセットをバンドルする例を考えてみましょう。これはかなり一般的な使用例です。プログラマーは、さまざまな種類の NFT をコレクションにパッケージ化したり、アイテムをまとめてマーケットプレイスで販売したり、既存のアイテムに添付ファイルを追加したりすることを希望する場合があります。次の状況があるとします。
アリスは、ゲームで使用するキャラクター オブジェクトを定義し、後で作成されるさまざまなタイプのサードパーティ アクセサリでキャラクターを装飾することをサポートしたいと考えています。 アクセサリは誰でも作成できるはずですが、アクセサリを追加するかどうかはキャラクターの所有者が決定する必要があります。 キャラクターを転送すると、そのすべてのアクセサリが自動的に転送されます。
今回はスイムーブのコードから始めてみましょう。ここでは、Sui ランタイムに組み込まれているオブジェクト所有権機能の別の側面を利用します。つまり、あるオブジェクトを別のオブジェクトが所有できるということです。すべてのオブジェクトには一意の所有者がいますが、親オブジェクトは任意の数の子オブジェクトを持つことができます。親オブジェクトと子オブジェクトの関係は、上で紹介した転送関数の関連オブジェクトである transfer_to_object 関数を使用して作成されます。
このコードでは、ロール モジュールに、ロール所有者が任意のタイプのアクセサリ オブジェクトを子オブジェクトとして追加できるアクセサリ関数が含まれています。これにより、ボブとクラリッサは、アリスにはないさまざまなプロパティと機能を備えた独自の装飾タイプを作成できますが、アリスがすでに行ったことに基づいています。たとえば、ボブのシャツはキャラクターの好きな色である場合にのみ装備でき、クラリッサの剣はキャラクターが十分に強力である場合にのみ装備できます。以下は Diem スタイル Move の実際的なデモンストレーションですが、どれも成功しませんでした。つまり、Diem スタイル Move は上記のシナリオを実現できません。
Diem スタイル Move の問題点は次のとおりであることがわかります。
(最初のテストで示されたように) 同じタイプのコレクションのみがサポートされますが、アクセサリは基本的にオブジェクトのタイプではありません。オブジェクト間の関係は「ラッピング」(つまり、あるオブジェクトを別のオブジェクト内に格納する) によってのみ実現できます。ラップできるオブジェクトのコレクションは、(2 回目のテストのように) 事前に定義するか、一時的な方法で追加する必要があります。(3 回目のテストのように) 追加のオブジェクトの構成はサポートされていません。
要約する
Sui は、Move の使用方法においてオリジナルの Diem 設計から大きく逸脱した最初のプラットフォームです。 Move とプラットフォームの独自機能を最大限に活用する組み合わせを設計することは芸術であると同時に科学でもあり、Move 言語と基盤となるブロックチェーンの機能についての深い理解が必要です。私たちは、Sui Move の進歩と、それによって可能になる新しいユースケースに非常に興奮しています。 [1] Diem スタイルの Move ポリシーを支持するもう 1 つの議論は、「特定のアセット タイプを受け取る前にオプトインする必要がある」というものです。これはスパムを防ぐための優れたメカニズムです。ただし、私たちはスパム防止について考えています。アプリケーション層に属するものとして、ユーザーがアセットの受信をオプトインするために実際のお金がかかるトランザクションの送信を要求するのではなく、豊富なユーザー定義ポリシーと自動スパムフィルターを使用して、(たとえば)ウォレットレベルでスパムに簡単に対処できます。 。


