Aula 022: Invocações Entre Programas (CPI)
Na blockchain Solana, programas podem interagir uns com os outros através das Invocações Entre Programas (CPI). Esse recurso poderoso permite que um programa chame e execute as instruções de outro programa, possibilitando um design modular e reutilização de código.
Nesta aula, vamos explorar como implementar o CPI em um programa Solana baseado em Rust. Abordaremos os seguintes tópicos:
- O que é CPI?
- Como configurar um programa básico da Solana que usa CPI.
- Exemplo de invocação de outro programa.
O que é CPI?
A Invocação Entre Programas permite que um programa Solana (também conhecido como contrato inteligente) chame funções em outro programa. Isso é significativo para a construção de aplicações complexas, pois permite a interoperabilidade entre diferentes programas.
Configurando um Programa Básico da Solana
Antes de mergulharmos no CPI, certifique-se de que seu ambiente de desenvolvimento está configurado para a Solana. Você deve ter o Rust e a CLI da Solana instalados. Se você é novato, pode inicializar um novo projeto:
cargo new solana_cpi_exemplo --lib
cd solana_cpi_exemplo
Adicionando Dependências
No seu Cargo.toml
, adicione as dependências necessárias:
[dependencies]
solana-program = "1.10.32" # Use a versão mais recente ao escrever
Criando o Programa
Para criar um programa simples que utiliza CPI, você irá criar dois programas separados. O primeiro programa (program_a
) será chamado pelo segundo programa (program_b
).
Programa A: Fornecendo funcionalidade via CPI
Vamos começar com o program_a
. Este programa incluirá uma instrução simples que pode ser invocada por outro programa.
Crie um novo diretório para program_a
e adicione o seguinte código a lib.rs
:
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint,
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
let accounts_iter = &mut accounts.iter();
let account_a = next_account_info(accounts_iter)?;
// Realizar lógica de negócios
msg!("Programa A invocado!");
msg!("Conta A: {:?}", account_a.key);
Ok(())
}
Compile e implemente o contrato inteligente program_a
no cluster da Solana usando a CLI da Solana.
Programa B: Invocando o Programa A
Agora vamos criar o program_b
, que fará a chamada ao program_a
.
No seu diretório program_b
, crie uma estrutura similar à anterior e adicione o seguinte código:
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint,
entrypoint::ProgramResult,
msg,
program::{invoke_signed, invoke},
pubkey::Pubkey,
program_error::ProgramError,
system_instruction,
};
entrypoint!(process_instruction);
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
let accounts_iter = &mut accounts.iter();
let account_b = next_account_info(accounts_iter)?;
let program_a_id = Pubkey::from_str("INSIRA_O_ID_DO_PROGRAM_A_AQUI").unwrap();
let accounts_to_pass = vec![account_b.clone()];
// Invocar o Programa A
invoke(
&system_instruction::create_account(
account_b.key,
&program_a_id,
1,
0,
&program_a_id,
),
&accounts_to_pass,
)?;
Ok(())
}
Invocando Outro Programa
Para chamar o program_a
do program_b
, você usa a função invoke
. Esta função recebe a instrução que você deseja chamar e as contas que serão passadas para essa instrução.
Certifique-se de substituir INSIRA_O_ID_DO_PROGRAM_A_AQUI
pelo ID real do programa program_a
, que você pode obter após a implementação.
Testando o CPI
Para testar sua configuração de CPI, você pode escrever um caso de teste simples, usando o framework de testes da Solana, para criar contas, invocar o program_b
, que por sua vez chama o program_a
, e verificar se as saídas estão como esperado.
Aqui está uma estrutura básica para um teste:
#[cfg(test)]
mod tests {
use super::*;
use solana_program::program_testing::*;
use solana_program::pubkey::Pubkey;
use solana_program::signature::Keypair;
use solana_sdk::{signature::Signer, transaction::Transaction};
#[tokio::test]
async fn test_cpi() {
let program_a_id = Pubkey::new_unique();
let program_b_id = Pubkey::new_unique();
let (mut banks_client, payer, recent_blockhash) = ProgramTest::new("program_a", program_a_id, processor!).start().await;
// Implemente o program_b e inicie o teste.
// Chame program_b que deve invocar program_a.
let transaction = Transaction::new_signed_with_payer(
&[instruction],
Some(&payer.pubkey()),
&[&payer],
recent_blockhash,
);
assert_eq!(banks_client.process_transaction(transaction).await.is_ok(), true);
}
}
Este teste inicializa ambos os programas, cria as contas necessárias e aciona o CPI. As instruções em program_a
aparecerão nos logs de transação se tudo for executado corretamente.
Conclusão
As Invocações Entre Programas são um recurso essencial da arquitetura da Solana que permite que programas trabalhem juntos, aumentando a modularidade e a reutilização de código. Nesta aula, passamos pela configuração de dois programas, escrevendo uma invocação simples de um para o outro, e discutimos brevemente como estruturar um teste para isso.
Experimente adicionar diferentes funcionalidades ao seu CPI e explore as infinitas possibilidades que ele oferece ao desenvolver na Solana!