Resumo
Uma instrução tem 3 campos: program_id (qual programa invocar), accounts
(lista AccountMeta com flags is_signer/is_writable) e data (array de bytes
de dados que o programa interpreta).
Estrutura de instruções
Uma
Instruction
consiste em três campos:
program_id: O ID do programa sendo invocado.accounts: Um array de metadados de contadata: Um array de bytes com dados adicionais a serem usados pela instrução.
pub struct Instruction {/// Pubkey of the program that executes this instruction.pub program_id: Pubkey,/// Metadata describing accounts that should be passed to the program.pub accounts: Vec<AccountMeta>,/// Opaque data passed to the program for its own interpretation.pub data: Vec<u8>,}
ID do programa
O program_id da instrução é o
endereço de chave pública do programa que contém a lógica de execução da
instrução. O runtime usa este campo para encaminhar a instrução ao programa
correto para processamento.
Metadados de conta
O array accounts da instrução é uma lista ordenada de estruturas
AccountMeta.
Os metadados devem ser fornecidos para cada conta com a qual a instrução
interage. O validador usa estes metadados para determinar quais transações podem
ser executadas em paralelo. Transações que escrevem em contas diferentes podem
ser executadas em paralelo.
O diagrama abaixo representa uma transação que contém uma única instrução. O
array accounts da instrução contém metadados para duas contas.
Uma transação com uma instrução. A instrução contém duas estruturas AccountMeta no seu array accounts.
Cada AccountMeta tem três campos:
- pubkey: O endereço de chave pública da conta
- is_signer: Definido como
truese a conta deve assinar a transação - is_writable: Definido como
truese a instrução modifica os dados da conta
Para saber quais contas uma instrução requer, incluindo quais devem ser graváveis, somente leitura ou assinar a transação, você deve consultar a implementação da instrução, conforme definida pelo programa.
pub struct AccountMeta {/// An account's public key.pub pubkey: Pubkey,/// True if an `Instruction` requires a `Transaction` signature matching `pubkey`.pub is_signer: bool,/// True if the account data or metadata may be mutated during program execution.pub is_writable: bool,}
Dados
O campo data da instrução é um array de bytes que informa ao programa qual
função invocar e fornece os argumentos para essa função. Os dados tipicamente
começam com um discriminador ou byte(s) de índice que identifica a função alvo,
seguido pelos argumentos serializados. O formato de codificação é definido por
cada programa (por exemplo, serialização Borsh ou um layout personalizado).
Convenções de codificação comuns:
- Programas principais (System, Stake, Vote): Usam um índice de variante enum serializado em Bincode seguido por argumentos serializados.
- Programas Anchor: Usam um discriminador de 8 bytes (os primeiros 8 bytes
do hash SHA-256 de
"global:<function_name>") seguido por argumentos serializados em Borsh.
O runtime não interpreta o campo data. Ele é passado como está para o ponto de
entrada process_instruction do programa.
Instrução compilada
Quando as instruções são serializadas numa mensagem de transação, elas tornam-se
estruturas
CompiledInstruction
que substituem todas as chaves públicas por índices inteiros compactos no array
account_keys da mensagem.
Exemplo: instrução de transferência de SOL
O exemplo abaixo mostra a estrutura de uma instrução de transferência de SOL.
import { generateKeyPairSigner, lamports } from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";// Generate sender and recipient keypairsconst sender = await generateKeyPairSigner();const recipient = await generateKeyPairSigner();// Define the amount to transferconst LAMPORTS_PER_SOL = 1_000_000_000n;const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL// Create a transfer instruction for transferring SOL from sender to recipientconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount});console.log(JSON.stringify(transferInstruction, null, 2));
O código abaixo mostra a saída dos trechos de código anteriores. O formato será
diferente entre SDKs, mas note que cada instrução contém as mesmas três
informações obrigatórias: program_id,
accounts, data.
{"accounts": [{"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC","role": 3,"signer": {"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC","keyPair": {"privateKey": {},"publicKey": {}}}},{"address": "2mBY6CTgeyJNJDzo6d2Umipw2aGUquUA7hLdFttNEj7p","role": 1}],"programAddress": "11111111111111111111111111111111","data": {"0": 2,"1": 0,"2": 0,"3": 0,"4": 128,"5": 150,"6": 152,"7": 0,"8": 0,"9": 0,"10": 0,"11": 0}}
Os exemplos abaixo mostram como construir manualmente a instrução de
transferência. (A aba Expanded Instruction é funcionalmente equivalente à aba
Instruction.)
Na prática, normalmente não é necessário construir uma Instruction
manualmente. A maioria dos programas fornece bibliotecas cliente com funções
auxiliares que criam as instruções para si. Se uma biblioteca não estiver
disponível, pode construir a instrução manualmente.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?