0. レビュー
- Secure the Solana Ecosystem (1) — Hello Solana
- Secure the Solana Ecosystem (2) — Calling Between Programs
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という属性をもう一つ追加します(18行目)。

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

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

5. 結論
この記事では、Solanaでプログラムがどのようにアップグレードできるかを紹介しました。詳細なプロセスを説明するために、さまざまな例を使用しました。乞うご期待ください。Solanaに関するさらなる記事を投稿する予定です。
このシリーズの他の記事を読む:
- Secure the Solana Ecosystem (1) — Hello Solana
- Secure the Solana Ecosystem (2) — Calling Between Programs
- Secure the Solana Ecosystem (4) — Account Validation
- Secure the Solana Ecosystem (5) — Multi-Sig
- Secure the Solana Ecosystem (6) — Multi-Sig2
- Secure the Solana Ecosystem (7) — Type Confusion
BlockSecについて
BlockSecは、2021年に世界的に著名なセキュリティ専門家グループによって設立された、先駆的なブロックチェーンセキュリティ企業です。同社は、Web3の普及を促進するために、新しい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



