Back to Blog

Solanaエコシステムを保護する(2)―プログラム間呼び出し

2022年3月18日
5 min read

0. レビュー

1. 概要

前回のブログでは、プログラムのデプロイとインタラクションの方法を紹介しました。クライアントサイドからプログラムの命令を呼び出す以外にも、 Solanaではクロスプログラム呼び出しと呼ばれるメカニズムを通じて、プログラム同士が呼び出し合うことも可能です。本稿では、クロスプログラム呼び出しがどのように使用されるかを説明します。テストコードはこちらにあります。

2. クロスプログラム呼び出し

クロスプログラム呼び出しは通常、invoke関数で実装されます。このセクションでは、プログラム内でlamportを転送する際のinvokeの使用法を説明します。

Solanaには、新しいアカウントの作成やlamport(SOL)の転送を担う、System Programというネイティブプログラムがあります。 この場合、プログラムAのようなプログラム内でlamportを転送するには、プログラムAはSystem Program内のtransfer()関数を呼び出します。具体的な例を以下に示します。

2.1 コードレビュー

3行目から10行目にかけて、必要なライブラリをインポートします。invoke()関数はsolana_program::programライブラリにあることに注意してください。

process_instruction関数において、22行目から30行目にかけて、クライアントによって渡された3つのアカウントを抽出します。lamportはfrom_accountからto_accountへ転送されます。33行目から44行目にかけて、invoke()関数が呼び出されます。この関数は2つの引数を受け取ります。1つ目は呼び出されるターゲット命令、2つ目はアカウントのセットです。 この例では、ターゲット命令はlamportの転送に使用されるtransfer()です。アカウントには、呼び出される命令に必要なすべてのアカウントが含まれます。この場合、from_accountto_accountです。

デプロイされたプログラムは以下のリンクで見つけることができます。

https://explorer.solana.com/address/EPaLuYQ4c11BJAe9ucLbta3xGFb17Zy3cZh3UDPbXRG9?cluster=devnet

2.2 Lamportの転送

前述の通り、トランザクションをデプロイされたプログラムに送信します。デプロイされたプログラムは、さらにSystem Programを呼び出してlamportをターゲットアドレスに転送します。 上記のコードは、クライアントがトランザクションを構築する方法を示しています。93行目から101行目にかけて、デプロイされたプログラムのprogramIdを抽出します。103行目から109行目にかけて、送信者、受信者、およびSystem Programのアドレスを生成します。111行目から117行目にかけて、トランザクションを構築します。118行目で、トランザクションはSolanaクラスタに送信されます。このトランザクションの唯一の署名者は送信者であることに注意してください。これは112行目で設定されています。送信者は、自分のアカウントから資金を引き出すトランザクションに承認(つまり署名)する必要がありますが、受信者は(113行目)署名する必要はありません。

トランザクションは以下のリンクで見つけることができます。

https://explorer.solana.com/tx/4cxqnff8SakVcE9y5phmh6utcbBUGaLDPvqMRgSy9aPGdNVH6DCsQyJXCCzRGvW5CpygUi5pqhgBQxczXnWCoqPJ?cluster=devnet

3. Invoke または Invoke_signed

Solanaでは、プログラムは実行時にプログラム由来アドレス(PDA)と呼ばれるアカウントを生成できます。プログラムによって呼び出されるターゲット命令にPDAを持つ署名済みアカウントが含まれる場合、invoke()の代わりにinvoke_signed()を使用する必要があります。invoke_signed()の使用法を実証するために、別の例を使用します。まず、コントラクトコードをレビューしましょう。

3.1 コードレビュー

この例では、プログラムB内で実行時にPDAを作成します。PDAを作成するには、System ProgramをプログラムBで呼び出す必要があります。

3行目から10行目にかけて、必要なライブラリをインポートします。今回はinvoke_signed()がインポートされていることに注意してください(6行目)。

セクション2の例と同様に、必要なアカウント(22〜27行目)を抽出します。これらはSystem ProgramとPDAです。次に、find_program_address()関数を使用して、PDAのアドレスと、このPDAをed25519曲線からオフセットするために使用されるシードを生成します(29〜30行目)。これは、アドレスに秘密鍵が関連付けられていないことを保証するためです。この例では、クライアントとプログラムは同じシード(つまり「You pass butter」)を使用してPDAを生成します。したがって、公開鍵は同じであるはずであり、これは31〜34行目で確認されます。その後、invoke_signerを呼び出して、37〜47行目のallocate()命令を発行します。invoke()関数とは異なり、PDAを作成するために使用されたシードと、find_program_address()関数によって使用されたバンプシードという、さらに1つの引数を受け取ります。

アカウントを作成/割り当てるには、アカウント自体が署名を提供する必要があります。この例ではPDAが署名者です。PDAに署名するには、invoke_signedが使用されます。具体的には、Solanaはシードと呼び出し元(プログラムB)のprogramIdを使用してPDAを再作成し、それを指定されたアカウント(2番目の引数)と一致させます。それらが等しい場合、PDAに署名されます。

デプロイされたプログラムは以下で確認できます。

https://explorer.solana.com/address/4h3RXGsouTRvUWNG1Dqq2tuuASTXFebHC3wFzv3tSFCK?cluster=devnet

3.2 PDAの作成

2番目の例のクライアントスクリプトを見てみましょう。

104行目で、findProgramAddress()関数を介してPDAとバンプシードを抽出します。 112行目から120行目にかけて、トランザクションが作成され、送信されます。ここでPDAのプロパティ(isSigner)は「false」(113行目)になります。これは、クライアントによって署名できないためです。実行時には、プログラムBがPDAに署名し、System Program内のallocate命令を呼び出します。

PDAが割り当てられたトランザクションは以下で見つけることができます。

https://explorer.solana.com/tx/5fzdfzbD4281pY1HJm37f1fxSEMGmWtQmbmFPzEiP9v6hWF8GRRZmfcMDvPJugTrs3npnCsaWUGvw15URyBhx3LS?cluster=devnet

3.3 Invoke()は使用できますか?

invokeが使用できないことを実証するために、別のプログラム(プログラムC)を使用してallocation命令を呼び出します。

唯一の変更点は、invoke_signed()関数をinvoke()関数に変更したことです。アカウントが作成できなかったことがわかりました。

エラーは、クロスプログラム呼び出しが正常に実行されるためには署名者が必要であることを示しています。つまり、invoke_signed()関数が必要です。

4. 結論

本記事では、invoke()関数を介してクロスプログラム呼び出しを実装する方法を紹介しました。また、invoke()invoke_signed()の違いを実証するために、さまざまな例を使用しました。引き続き、このシリーズの他の記事も公開予定です。

このシリーズの他の記事を読む:

Sign up for the latest updates
約940万ドルの損失:Injective、Aquiferのエクスプロイト | BlockSec Weekly
Security Insights

約940万ドルの損失:Injective、Aquiferのエクスプロイト | BlockSec Weekly

先週(2026/08/31~09/06)、Injective、Solana、Ethereum、Flow EVMで4件の攻撃が発生し損失は約940万ドル。Injectiveは保険基金IDとオプション市場IDの衝突で約480万ドル、SolanaのAquiferは未検証Token Programで約247万ドル、EthereumのNotional Finance V1は`uint128`キャスト不備で約173万ドル、Flow EVMのAnkr FLOWは一時停止回避と古い比率発行で約41万ドルを失った。

スマートコントラクトを超えて:Web3におけるドメインとDNSの運用セキュリティ
Security Insights

スマートコントラクトを超えて:Web3におけるドメインとDNSの運用セキュリティ

コントラクト監査は契約書止まり。DefiLlama TVL上位100件のドメインにSEAL基準のDNS・レジストラ検査を8項目、計800回実施した結果、全通過は1件のみ。多くのプロジェクトに欠けている4つの管理策と、ユーザーの入口での重要性を解説。

約2,300万ドル喪失:Cosmos EVM、Moonwellの被害事例 | BlockSec Weekly
Security Insights

約2,300万ドル喪失:Cosmos EVM、Moonwellの被害事例 | BlockSec Weekly

レポート期間(2026/08/22-2026/08/30)中、約2270万ドルの損害を伴う5件のブロックチェーンセキュリティ事件を報告。Tectonicから約7400万〜1.195億ドルが流出したが、CronosがExploit前状態にロールバックされ大部分が消失。ハイライトはTAC Chainで追跡された6チェーンにわたるCosmos EVM Exploitシリーズ(実現損失約570万ドル)で、共有残高同期バグがアンダーフローとオーバーフローを連鎖させステーキングプールを枯渇させた。Moonwellの担保会計とオラクル価格操作の複合、Tectonicのオラクル価格とレシートトークン交換レート操作、Ajnaの清算ビジネスロジック欠陥、SolanaのRain Card Contract ExploitシリーズにおけるEd25519署名検証バイパス(Avici、Tria等)も分析。