You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solana原生代码中CPI调用时,被调用程序如何获取并验证调用方Program ID?

在Solana中CPI调用时验证调用方程序ID的方案

核心逻辑

Solana的Runtime会自动维护CPI调用的调用栈上下文,调用方的程序ID会被Runtime自动记录,不需要手动传递。ProgramB可以直接通过Solana提供的API读取这个上下文里的调用方ID,完全不存在被篡改的可能,这和Solidity中msg.sender的可信性一致。

具体实现(以Rust为例)

在ProgramB的指令处理函数中,通过Solana SDK的invoke_context()API获取直接调用方的程序ID,然后和预设的ProgramA ID做对比即可:

use solana_program::{
    account_info::AccountInfo,
    entrypoint::ProgramResult,
    program_error::ProgramError,
    pubkey::Pubkey,
    invoke_context,
};

// 预先定义ProgramA的程序ID
const EXPECTED_CALLER: Pubkey = Pubkey::new_from_array([/* 替换为ProgramA的公钥字节数组 */]);

pub fn process_instruction(
    _program_id: &Pubkey,
    _accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    // 从Runtime上下文获取直接调用方的程序ID
    let caller_id = invoke_context::get_invoke_context()?.caller_program_id();

    // 验证调用方是否为ProgramA
    if caller_id != &EXPECTED_CALLER {
        return Err(ProgramError::InvalidCaller);
    }

    // 执行后续业务逻辑
    Ok(())
}

关于"手动传递账户"的问题

你提到的手动传递调用方账户的方案不可靠,因为发起CPI的ProgramA可以随意传入任意账户公钥,无法确保这个账户就是真实的调用程序。而通过Runtime调用栈获取的ID是由Solana节点维护的,任何用户程序都无法修改这个上下文信息,完全可信。

补充说明

如果是多层嵌套CPI(比如ProgramA → ProgramB → ProgramC),caller_program_id()获取的是直接上层的调用方(ProgramC拿到的是ProgramB的ID)。如果需要追溯最顶层的发起程序,可以通过invoke_context().call_stack()遍历整个调用栈,但绝大多数场景下验证直接调用方就足够满足需求。

内容的提问来源于stack exchange,提问作者Neo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 10:46:01