CPI (Cross-Program Invocation)
概念简介
CPI(跨程序调用)是 Solana 区块链中一个重要的机制,允许一个程序直接调用另一个程序的指令。这是 Solana 实现程序可组合性的核心特性。
如果把 Solana 指令比作程序向网络公开的 API 端点,那么 CPI 就像是一个端点在内部调用另一个端点。通过 CPI,开发者可以构建复杂的、模块化的应用程序,充分利用现有程序的功能。
工作原理
当程序 A 调用程序 B 的指令时,账户权限会从一个程序扩展到另一个程序。程序 B 可以使用与程序 A 相同的账户及其原始权限,这意味着:
- 程序 B 可以使用签名者账户进行签名
- 程序 B 可以写入可写账户
这种权限传递机制确保了跨程序调用的安全性和一致性。
核心特性
账户权限扩展
- 被调用程序继承调用程序的账户权限
- 保持原始账户的可写和签名属性
- 确保权限链的安全传递
PDA 签名
- 程序可以代表从其程序 ID 派生的 PDA(程序派生地址)进行签名
- 签名者权限从调用程序扩展到被调用程序
- 允许程序在没有私钥的情况下控制账户
调用深度限制
- 堆栈高度从初始交易的 1 开始
- 每次程序调用另一个指令时,堆栈高度增加 1
- CPI 调用深度限制为 4 层
- 防止无限递归和资源耗尽
实现方法
Solana 提供了两种主要的 CPI 实现方式:
invoke 函数
- 用于不需要 PDA 签名者的 CPI
- 适用于简单的跨程序调用场景
- 内部实际调用
invoke_signed函数,传递空的签名种子数组
invoke_signed 函数
- 用于需要 PDA 签名者的 CPI
- 传递 PDA 的种子用于签名验证
- 允许程序代表其派生的 PDA 进行操作
使用场景
- DeFi 协议组合:DEX 调用借贷协议,实现闪电贷交易
- NFT 市场:市场程序调用 Token 程序转移 NFT 所有权
- 跨链桥:桥接程序调用多个 Token 程序处理资产转移
- 游戏应用:游戏逻辑程序调用 NFT 铸造程序生成游戏道具
- DAO 治理:治理程序调用国库程序执行提案
最佳实践
- 验证账户:在进行 CPI 之前,始终验证传入的账户
- 检查程序 ID:确保调用的是预期的程序
- 处理错误:适当处理被调用程序可能返回的错误
- 优化调用深度:避免不必要的深层嵌套调用
- 安全性考虑:注意重入攻击和权限提升风险