0. レビュー
1. 概要
前回のブログでは、invoke関数とinvoke_signed関数によるクロスプログラム呼び出しの実装方法をご紹介しました。本稿では、もう一つの基本的なトピックであるプログラムのアップグレードについてご紹介します。
2. アップグレード可能なプログラムのデプロイ
デフォルトでは、Solanaにデプロイされるすべてのプログラムは、BPFLoaderUpgradeableローダーを使用してデプロイされます。これは、プログラムがアップグレード可能であることを意味します。これに加えて、Solanaは--finalオプションを提供しており、デプロイされたプログラムが不変であることを保証します。この場合、プログラムのデプロイにはBPFLoader2ローダーが使用されます。デプロイ後は、プログラムのアップグレードはできません。
BPFLoaderUpgradeableローダープログラムは、プログラムアカウント、プログラムデータアカウント、バッファアカウントの3種類のアカウントを管理します。デプロイプロセスでは、まずバッファアカウントが作成されます。その後、Solana CLIはターゲットプログラムのバイトコードをロードし、バッファアカウントに書き込みます。最終的に、バッファアカウントに格納されたバイトコードはプログラムデータアカウントにコピーされます。
このように、バッファアカウントはアップグレード可能なBPFローダーがデプロイプロセス中にバイトコードを一時的に格納するために使用され、プログラムデータアカウントはプログラムの実際のデータを格納し、プログラムアカウントは対応するプログラムデータアカウントを指すプロキシとして機能します。
以下では、プログラムをアップグレードする方法について、いくつかのサンプルを見ていきます。本稿で使用するコードはすべてこちらで見つけることができます。
2.1 コードレビュー (Rectangle_Area)

このサンプルコントラクトでは、13行目から17行目にかけて、width、height、areaの3つの属性を持つRectangleという構造体を定義しています。また、Rectangle用のarea()関数も定義しています。area()関数は、widthとheightを使用して長方形の面積を計算します。

process_instruction()関数では、まずunpack_u32()関数を使用して、命令データから長方形のwidthとheightを抽出します(45行目-46行目)。51行目では、長方形のデータを格納するために使用されるアカウントを抽出します。59行目では、try_from_slice_unchecked()関数を使用して、アカウントのデータをRectangle構造体の型でデシリアライズします。次に、データを構造体の対応するフィールドに割り当て、面積の値を計算します(61行目-63行目)。最後のステップは、データをシリアライズし、データアカウントに書き戻すことです。
デプロイされたプログラムは、以下のリンクで見ることができます。
https://explorer.solana.com/address/84mMqHRTQT6b2vfsD7XRxVKA3XMd7xoEXFdF6pLNw8y?cluster=testnet
2.2 トランザクションの送信

クライアント側では、まずデータを格納するためアカウントを作成するトランザクションを送信します。十分なスペースを確保するため、スペースサイズを1,024バイトに設定します。

次に、長方形の面積を計算し、データアカウントに格納するための別のトランザクションを送信します。
トランザクションは以下のリンクで見ることができます。
https://explorer.solana.com/tx/4PybjXGRpuPKpak7FAz4BKMbcQCWmway69zAxtTnpFRuTTg7onyxW7agSe6ETx44iAGexbgnBUa8WdzdTTQSawJ3?cluster=testnet
3. アップグレード
ここで、プログラムに新しい関数を追加して、長方形の周囲長を計算できるようにします。

更新されたプロジェクトをコンパイルした後、以下のコマンドでオンチェーンのデプロイ済みプログラムをアップグレードします。
solana program deploy /path/to/program.so --program-id <PROGRAM_ID>
コントラクトは直接アップグレードでき、関連するトランザクションは以下で確認できます。
https://explorer.solana.com/tx/4Dm9v4zMiijKjQBhatx1D9xbV9PvMLdaonUWLaC2VwzkFvzdgorzbX5vsy4VQ7VxSUmqadftjiDzbyUmXgQchYmk?cluster=testnet
さらに、プログラムにトランザクションを送信して、正常にアップグレードされたことを確認します。結果は、関数が正常に機能していることを示しています。
関連するトランザクションは以下で見ることができます。
https://explorer.solana.com/tx/21c2G7kPVktAtdUFkH3QwGVi7orajRmy5PJo1UxX1mmAMU68eUkNuLzWYJRBaTzwGi5DxeocYjHfpWiU4hcSFtpQ?cluster=testnet
4. 再度アップグレード

今回は、計算された周囲長をデータアカウントに格納することにします。この場合、構造体Rectangleにperimeterという属性を1つ追加します(18行目)。

データアカウントの構造体が以前のものと異なるため、まずデータアカウントからデータを読み取る必要があります。以前の構造体(つまりOldRectangle)を使用して格納されたデータをデシリアライズします。その後、対応する属性を新しい構造体(つまりCurrentRectangle)に割り当て、新しい属性(つまりperimeter)を初期化します。

最後に、周囲長の値を計算し、それをupdate_accountに割り当ててから、account_dataにシリアライズします。
アップグレードのためのトランザクションは以下で見ることができます。
https://explorer.solana.com/tx/5J3oKxZXtCi755gD7pMnVh48AFvmeVzRLPgJiyNn8JFeCKx1xpAfJtsi34zjyYKJmnMk8LtC3bcwfFSP7H2gtj5o?cluster=testnet
アップグレード後、solana account <DataAccount>コマンドでアカウントに格納されているデータをチェックできます。属性は最初の32バイトに格納されていることがわかります。これでアップグレードプロセス全体が完了しました。

5. 結論
この記事では、Solanaでプログラムをアップグレードする方法について説明しました。詳細なプロセスを説明するために、さまざまな例を使用しました。続報にご期待ください。Solanaに関する記事は今後も掲載していきます。
このシリーズの他の記事を読む:
- Solanaエコシステムの保護 (1) — Hello Solana
- Solanaエコシステムの保護 (2) — プログラム間の呼び出し
- Solanaエコシステムの保護 (4) — アカウント検証
- Solanaエコシステムの保護 (5) — マルチシグ
- Solanaエコシステムの保護 (6) — マルチシグ2
- Solanaエコシステムの保護 (7) — 型の混乱
BlockSecについて
BlockSecは、世界的に著名なセキュリティ専門家グループによって2021年に設立された、最先端のブロックチェーンセキュリティ企業です。当社は、Web3の世界のセキュリティとユーザビリティを向上させ、その大規模な普及を促進することに尽力しています。この目的のため、BlockSecはスマートコントラクトとEVMチェーンのセキュリティ監査サービス、セキュリティ開発と脅威のプロアクティブなブロックのためのPhalconプラットフォーム、資金追跡と調査のためのMetaSleuthプラットフォーム、そしてWeb3ビルダーが仮想通貨の世界を効率的にサーフィンするためのMetaSuites拡張機能を提供しています。
現在までに、MetaMask、Uniswap Foundation、Compound、Forta、PancakeSwapなど300社を超える著名なクライアントにサービスを提供し、Matrix Partners、Vitalbridge Capital、Fenbushi Capitalなどの著名な投資家から2回の資金調達で数千万米ドルを獲得しています。
公式ウェブサイト: https://blocksec.com/
公式Twitterアカウント: https://twitter.com/BlockSecTeam



