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)

このサンプルコントラクトでは、width、height、areaの3つの属性を持つRectangleという名前の構造体を13行目から17行目に定義しています。また、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に関する記事を投稿していく予定です。
このシリーズの他の記事を読む:
- 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の世界のセキュリティと使いやすさを向上させ、その大規模な普及を促進することに尽力しています。この目的のため、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



