SwiftHTML & CSSSolidityDesenvolvimento de JogosSolana/Rust
14.11.2024

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:

  1. O que é CPI?
  2. Como configurar um programa básico da Solana que usa CPI.
  3. 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!

Did you like this article? Rate it from 1 to 5:

Thank you for voting!