跨程序调用
在本节中,将通过添加跨程序调用(CPI)功能来更新上一节 PDA 中的 CRUD 程序。CPI 是一种允许 Solana 程序相互调用的功能。
本教程还展示了在进行跨程序调用时,程序如何为程序派生地址(PDA)“签名”。
需要修改 update
和 delete
指令,以通过调用系统程序来处理账户之间的 SOL 转账。
本节的目的是通过使用 Anchor 框架在 Solana 程序中实现 CPI 的过程,基于上一节中探索的 PDA 概念进行构建。有关更多详细信息,请参阅跨程序调用页面。
作为参考,此链接包含最终代码,完成 PDA 和 CPI 部分后可查看。
本节的起始代码仅包括完成的 PDA 部分。
更新 Update 指令
首先,通过更改 Update
结构体和 update
函数,为程序添加一个简单的“付费更新”机制。
首先更新 lib.rs
文件,以引入 system_program
模块中的项目。
use anchor_lang::system_program::{transfer, Transfer};
接下来,更新 Update
结构体,添加一个名为 vault_account
的新账户。该账户由程序控制,当用户更新其消息账户时接收 SOL。
#[account(mut,seeds = [b"vault", user.key().as_ref()],bump,)]pub vault_account: SystemAccount<'info>,
接下来,在 update
指令中添加 CPI 逻辑,将 0.001 SOL 从用户账户转移到金库账户。
let transfer_accounts = Transfer {from: ctx.accounts.user.to_account_info(),to: ctx.accounts.vault_account.to_account_info(),};let cpi_context = CpiContext::new(ctx.accounts.system_program.to_account_info(),transfer_accounts,);transfer(cpi_context, 1_000_000)?;
重新构建程序。
$build
更新删除指令
现在通过更改 Delete
结构体和 delete
函数,添加一个“删除时退款”机制。
首先,更新 Delete
结构体,以包含
vault_account
。这允许在用户关闭其消息账户时,将金库中的任何 SOL 转回给用户。
#[account(mut,seeds = [b"vault", user.key().as_ref()],bump,)]pub vault_account: SystemAccount<'info>,
还需添加 system_program
,因为转账的 CPI 需要调用系统程序。
pub system_program: Program<'info, System>,
接下来,在 delete
指令中添加 CPI 逻辑,将 SOL 从金库账户转回用户账户。
let user_key = ctx.accounts.user.key();let signer_seeds: &[&[&[u8]]] =&[&[b"vault", user_key.as_ref(), &[ctx.bumps.vault_account]]];let transfer_accounts = Transfer {from: ctx.accounts.vault_account.to_account_info(),to: ctx.accounts.user.to_account_info(),};let cpi_context = CpiContext::new(ctx.accounts.system_program.to_account_info(),transfer_accounts,).with_signer(signer_seeds);transfer(cpi_context, ctx.accounts.vault_account.lamports())?;
请注意,_ctx: Context<Delete>
更改为
ctx: Context<Delete>
,以便在函数主体中使用上下文。
重新构建程序。
$build
重新部署程序
完成这些更改后,重新部署更新后的程序。这确保了修改后的程序可以用于测试。在 Solana 上,更新程序只需将程序部署到相同的程序 ID 即可。
确保您的 Playground 钱包中有 devnet SOL。可以从 Solana Faucet 获取 devnet SOL。
$deploy
更新测试文件
接下来,更新 anchor.test.ts
文件以在指令中包含新的保险库账户。这需要派生保险库 PDA 并将其包含在更新和删除指令调用中。
推导 Vault PDA
首先,添加 Vault PDA 的推导:
const [vaultPda, vaultBump] = PublicKey.findProgramAddressSync([Buffer.from("vault"), wallet.publicKey.toBuffer()],program.programId);
修改更新测试
然后,更新指令以包含 vaultAccount
const transactionSignature = await program.methods.update(message).accounts({messageAccount: messagePda,vaultAccount: vaultPda}).rpc({ commitment: "confirmed" });
修改删除测试
然后,更新删除指令以包含 vaultAccount
const transactionSignature = await program.methods.delete().accounts({messageAccount: messagePda,vaultAccount: vaultPda}).rpc({ commitment: "confirmed" });
下一步
恭喜您完成了 Solana 快速入门指南。您已经通过实践掌握了以下关键的 Solana 概念:
- 从账户中获取和读取数据
- 构建和发送交易
- 部署和更新 Solana 程序
- 使用程序派生地址 (PDAs)
- 进行跨程序调用 (CPIs)
为了加深对这些概念的理解,请查看 核心概念 文档,其中提供了本指南中涵盖主题的详细解释。
探索更多示例
如果您更喜欢通过示例学习,请查看 程序示例库,其中包含各种示例程序。
Solana Playground 提供了一个便捷功能,允许您通过 GitHub 链接导入或查看项目。例如,打开此 Solana Playground 链接 以查看此 Github 仓库 中的 Anchor 项目。
点击 Import
按钮,输入项目名称,将其添加到您在 Solana
Playground 中的项目列表中。一旦项目被导入,所有更改都会自动保存并持久化。
Is this page helpful?