Program Derived Address
Nesta seção, você aprenderá como construir um programa básico de Criar, Ler, Atualizar, Excluir (CRUD).
Este guia demonstra um programa simples onde os usuários podem criar, atualizar e excluir uma mensagem. Cada mensagem existe em uma conta com um endereço determinístico derivado do próprio programa (Program Derived Address ou PDA).
Este guia orienta você na construção e teste de um programa Solana usando o framework Anchor enquanto demonstra Program Derived Addresses (PDAs). Para mais detalhes, consulte a página Program Derived Addresses.
Para referência, você pode visualizar o código final após completar as seções de PDA e Cross Program Invocation (CPI).
Código inicial
Comece abrindo este link do Solana Playground com o código inicial. Em seguida, clique no botão "Import" para adicionar o programa aos seus projetos do Solana Playground.
Importar
No arquivo lib.rs
, você encontrará um programa com as instruções
create
, update
e delete
para adicionar nos passos seguintes.
use anchor_lang::prelude::*;declare_id!("8KPzbM2Cwn4Yjak7QYAEH9wyoQh86NcBicaLuzPaejdw");#[program]pub mod pda {use super::*;pub fn create(_ctx: Context<Create>) -> Result<()> {Ok(())}pub fn update(_ctx: Context<Update>) -> Result<()> {Ok(())}pub fn delete(_ctx: Context<Delete>) -> Result<()> {Ok(())}}#[derive(Accounts)]pub struct Create {}#[derive(Accounts)]pub struct Update {}#[derive(Accounts)]pub struct Delete {}#[account]pub struct MessageAccount {}
Antes de começar, execute build
no terminal do Playground para
verificar se o programa inicial compila com sucesso.
$build
Definir o tipo de conta de mensagem
Primeiro, defina a estrutura para a conta de mensagem que o programa cria. Esta estrutura define os dados a serem armazenados na conta criada pelo programa.
Em lib.rs
, atualize a estrutura MessageAccount
com o seguinte:
#[account]pub struct MessageAccount {pub user: Pubkey,pub message: String,pub bump: u8,}
Compile o programa novamente executando build
no terminal.
$build
Este código define quais dados armazenar na conta de mensagem. Em seguida, você adicionará as instruções do programa.
Adicionar instrução de criação
Agora, adicione a instrução create
que cria e inicializa o
MessageAccount
.
Comece definindo as contas necessárias para a instrução atualizando a estrutura
Create
com o seguinte:
#[derive(Accounts)]#[instruction(message: String)]pub struct Create<'info> {#[account(mut)]pub user: Signer<'info>,#[account(init,seeds = [b"message", user.key().as_ref()],bump,payer = user,space = 8 + 32 + 4 + message.len() + 1)]pub message_account: Account<'info, MessageAccount>,pub system_program: Program<'info, System>,}
Em seguida, adicione a lógica de negócios para a instrução create
atualizando a função create
com o seguinte:
pub fn create(ctx: Context<Create>, message: String) -> Result<()> {msg!("Create Message: {}", message);let account_data = &mut ctx.accounts.message_account;account_data.user = ctx.accounts.user.key();account_data.message = message;account_data.bump = ctx.bumps.message_account;Ok(())}
Reconstrua o programa.
$build
Adicionar instrução de atualização
Em seguida, adicione a instrução update
para alterar o MessageAccount
com
uma nova mensagem.
Como na etapa anterior, primeiro especifique as contas necessárias para a
instrução update
.
Atualize a estrutura Update
com o seguinte:
#[derive(Accounts)]#[instruction(message: String)]pub struct Update<'info> {#[account(mut)]pub user: Signer<'info>,#[account(mut,seeds = [b"message", user.key().as_ref()],bump = message_account.bump,realloc = 8 + 32 + 4 + message.len() + 1,realloc::payer = user,realloc::zero = true,)]pub message_account: Account<'info, MessageAccount>,pub system_program: Program<'info, System>,}
Em seguida, adicione a lógica para a instrução update
.
pub fn update(ctx: Context<Update>, message: String) -> Result<()> {msg!("Update Message: {}", message);let account_data = &mut ctx.accounts.message_account;account_data.message = message;Ok(())}
Reconstrua o programa
$build
Adicionar instrução de exclusão
Em seguida, adicione a instrução delete
para fechar o
MessageAccount
.
Atualize a estrutura Delete
com o seguinte:
#[derive(Accounts)]pub struct Delete<'info> {#[account(mut)]pub user: Signer<'info>,#[account(mut,seeds = [b"message", user.key().as_ref()],bump = message_account.bump,close = user,)]pub message_account: Account<'info, MessageAccount>,}
Em seguida, adicione a lógica para a instrução delete
.
pub fn delete(_ctx: Context<Delete>) -> Result<()> {msg!("Delete Message");Ok(())}
Reconstrua o programa.
$build
Implantar o programa
Você agora completou o programa CRUD básico. Implante o programa executando
deploy
no terminal do Playground.
Neste exemplo, você implantará o programa na devnet, um cluster Solana para testes de desenvolvimento.
A carteira do Playground conecta-se à devnet por padrão. Certifique-se de que sua carteira do Playground tenha SOL da devnet para pagar pela implantação do programa. Obtenha SOL da devnet no Solana Faucet.
$deploy
Configurar arquivo de teste
O código inicial também inclui um arquivo de teste em anchor.test.ts
.
import { PublicKey } from "@solana/web3.js";describe("pda", () => {it("Create Message Account", async () => {});it("Update Message Account", async () => {});it("Delete Message Account", async () => {});});
Adicione o código abaixo dentro de describe()
, mas antes das seções
it()
.
const program = pg.program;const wallet = pg.wallet;const [messagePda, messageBump] = PublicKey.findProgramAddressSync([Buffer.from("message"), wallet.publicKey.toBuffer()],program.programId);
Execute o arquivo de teste rodando test
no terminal do Playground para
verificar se ele funciona como esperado. Os próximos passos adicionam os testes
reais.
$test
Invocar a instrução Create
Atualize o primeiro teste com o seguinte:
it("Create Message Account", async () => {const message = "Hello, World!";const transactionSignature = await program.methods.create(message).accounts({messageAccount: messagePda}).rpc({ commitment: "confirmed" });const messageAccount = await program.account.messageAccount.fetch(messagePda,"confirmed");console.log(JSON.stringify(messageAccount, null, 2));console.log("Transaction Signature:",`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`);});
Invocar instrução de atualização
Atualize o segundo teste com o seguinte:
it("Update Message Account", async () => {const message = "Hello, Solana!";const transactionSignature = await program.methods.update(message).accounts({messageAccount: messagePda}).rpc({ commitment: "confirmed" });const messageAccount = await program.account.messageAccount.fetch(messagePda,"confirmed");console.log(JSON.stringify(messageAccount, null, 2));console.log("Transaction Signature:",`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`);});
Invocar instrução de exclusão
Atualize o terceiro teste com o seguinte:
it("Delete Message Account", async () => {const transactionSignature = await program.methods.delete().accounts({messageAccount: messagePda}).rpc({ commitment: "confirmed" });const messageAccount = await program.account.messageAccount.fetchNullable(messagePda,"confirmed");console.log("Expect Null:", JSON.stringify(messageAccount, null, 2));console.log("Transaction Signature:",`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`);});
Executar teste
Depois de preparar seus testes, execute o arquivo de teste com test
no
terminal do Playground. Este comando executa os testes contra o programa
implantado na devnet e registra links para o SolanaFM para visualizar os
detalhes da transação.
$test
Inspecione os links do SolanaFM para visualizar os detalhes da transação.
Observe que neste exemplo, se você executar o teste novamente, a instrução
create
falha porque messageAccount
já existe como uma conta. Apenas uma
conta pode existir para um determinado PDA.
Is this page helpful?