Resumen
Una instrucción tiene 3 campos: program_id (qué programa invocar),
accounts (lista AccountMeta con banderas is_signer/is_writable) y data
(array de bytes de datos que el programa interpreta).
Estructura de instrucciones
Una
Instruction
consiste en tres campos:
program_id: El ID del programa que se invoca.accounts: Un array de metadatos de cuentadata: Un array de bytes con datos adicionales para ser utilizados por la instrucción.
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 de programa
El program_id de la instrucción es
la dirección de clave pública del programa que contiene la lógica de ejecución
de la instrucción. El runtime utiliza este campo para enrutar la instrucción al
programa correcto para su procesamiento.
Metadatos de cuenta
El array accounts de la instrucción es una lista ordenada de estructuras
AccountMeta.
Se deben proporcionar metadatos para cada cuenta con la que interactúa la
instrucción. El validador utiliza estos metadatos para determinar qué
transacciones pueden ejecutarse en paralelo. Las transacciones que escriben en
cuentas diferentes pueden ejecutarse en paralelo.
El diagrama a continuación muestra una transacción que contiene una sola
instrucción. El array accounts de la instrucción contiene metadatos para dos
cuentas.
Una transacción con una instrucción. La instrucción contiene dos estructuras AccountMeta en su array accounts.
Cada AccountMeta tiene tres campos:
- pubkey: La dirección de clave pública de la cuenta
- is_signer: Se establece en
truesi la cuenta debe firmar la transacción - is_writable: Se establece en
truesi la instrucción modifica los datos de la cuenta
Para saber qué cuentas requiere una instrucción, incluyendo cuáles deben ser escribibles, de solo lectura o firmar la transacción, debes consultar la implementación de la instrucción, tal como está definida por el 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,}
Datos
El campo data de la instrucción es un array de bytes que indica al programa
qué función invocar y proporciona los argumentos para esa función. Los datos
típicamente comienzan con un discriminador o byte(s) de índice que identifica la
función objetivo, seguido de los argumentos serializados. El formato de
codificación está definido por cada programa (por ejemplo, serialización Borsh o
un diseño personalizado).
Convenciones de codificación comunes:
- Programas principales (System, Stake, Vote): Utilizan un índice de variante enum serializado con Bincode seguido de argumentos serializados.
- Programas Anchor: Utilizan un discriminador de 8 bytes (los primeros 8
bytes del hash SHA-256 de
"global:<function_name>") seguido de argumentos serializados con Borsh.
El runtime no interpreta el campo data. Se pasa tal cual al punto de entrada
process_instruction del programa.
Instrucción compilada
Cuando las instrucciones se serializan en un mensaje de transacción, se
convierten en estructuras
CompiledInstruction
que reemplazan todas las claves públicas con índices enteros compactos en el
array account_keys del mensaje.
Ejemplo: instrucción de transferencia de SOL
El ejemplo a continuación muestra la estructura de una instrucción de transferencia 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));
El código a continuación muestra la salida de los fragmentos de código
anteriores. El formato difiere entre SDKs, pero observa que cada instrucción
contiene las mismas tres piezas de información requerida:
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}}
Los ejemplos a continuación muestran cómo construir manualmente la instrucción
de transferencia. (La pestaña Expanded Instruction es funcionalmente
equivalente a la pestaña Instruction).
En la práctica, normalmente no tienes que construir una Instruction
manualmente. La mayoría de los programas proporcionan bibliotecas cliente con
funciones auxiliares que crean las instrucciones por ti. Si no hay una
biblioteca disponible, puedes construir la instrucción manualmente.
const transferAmount = 0.01; // 0.01 SOLconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount * LAMPORTS_PER_SOL});
Is this page helpful?