Riepilogo
Un'istruzione ha 3 campi: program_id (quale programma invocare), accounts
(lista AccountMeta con flag is_signer/is_writable) e data (array di byte di
dati che il programma interpreta).
Struttura delle istruzioni
Un'
Instruction
consiste di tre campi:
program_id: l'ID del programma che viene invocato.accounts: un array di metadati dell'accountdata: un array di byte con dati aggiuntivi da utilizzare per l'istruzione.
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 del programma
Il program_id dell'istruzione è
l'indirizzo della chiave pubblica del programma che contiene la logica di
esecuzione dell'istruzione. Il runtime utilizza questo campo per instradare
l'istruzione al programma corretto per l'elaborazione.
Metadati dell'account
L'array accounts dell'istruzione è una lista ordinata di struct
AccountMeta.
Devono essere forniti metadati per ogni account con cui l'istruzione
interagisce. Il validator utilizza questi metadati per determinare quali
transazioni possono essere eseguite in parallelo. Le transazioni che scrivono su
account diversi possono essere eseguite in parallelo.
Il diagramma seguente mostra una transazione che contiene una singola
istruzione. L'array accounts dell'istruzione contiene metadati per due
account.
Una transazione con un'istruzione. L'istruzione contiene due struct AccountMeta nel suo array accounts.
Ogni struct AccountMeta ha tre campi:
- pubkey: l'indirizzo della chiave pubblica dell'account
- is_signer: impostato su
truese l'account deve firmare la transazione - is_writable: impostato su
truese l'istruzione modifica i dati dell'account
Per sapere quali account richiede un'istruzione, inclusi quali devono essere scrivibili, di sola lettura o firmare la transazione, devi fare riferimento all'implementazione dell'istruzione, come definita dal programma.
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,}
Dati
Il campo data dell'istruzione è un array di byte che indica al programma quale
funzione invocare e fornisce gli argomenti per quella funzione. I dati
tipicamente iniziano con un discriminatore o byte di indice che identifica la
funzione target, seguito dagli argomenti serializzati. Il formato di codifica è
definito da ciascun programma (ad esempio, serializzazione Borsh o un layout
personalizzato).
Convenzioni di codifica comuni:
- Programmi core (System, Stake, Vote): utilizzano un indice di variante enum serializzato con Bincode seguito da argomenti serializzati.
- Programmi Anchor: utilizzano un discriminatore a 8 byte (i primi 8 byte
dell'hash SHA-256 di
"global:<function_name>") seguito da argomenti serializzati con Borsh.
Il runtime non interpreta il campo data. Viene passato così com'è
all'entrypoint process_instruction del programma.
Istruzione compilata
Quando le istruzioni vengono serializzate in un messaggio di transazione,
diventano struct
CompiledInstruction
che sostituiscono tutte le chiavi pubbliche con indici interi compatti
nell'array account_keys del messaggio.
Esempio: istruzione di trasferimento SOL
L'esempio seguente mostra la struttura di un'istruzione di trasferimento 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));
Il codice seguente mostra l'output degli snippet di codice precedenti. Il
formato sarà diverso tra gli SDK, ma nota che ogni istruzione contiene le stesse
tre informazioni richieste: 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}}
Gli esempi seguenti mostrano come costruire manualmente l'istruzione di
trasferimento. (La scheda Expanded Instruction è funzionalmente equivalente
alla scheda Instruction.)
In pratica, di solito non è necessario costruire un'Instruction
manualmente. La maggior parte dei programmi fornisce librerie client con
funzioni helper che creano le istruzioni per te. Se una libreria non è
disponibile, puoi costruire manualmente l'istruzione.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?