Manejadores de Instrucciones
Los manejadores de instrucciones son funciones públicas dentro de #[program]. Reciben Context<T> donde T es la estructura de cuentas validada, más cualquier argumento deserializado por Borsh.
Receta
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
require!(amount > 0, VaultError::InvalidAmount);
// business logic
Ok(())
}Cuándo usar esto: Implementas la lógica de negocio para una instrucción en la cadena.
Ejemplo Funcional
#[program]
pub mod vault {
use super::*;
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
let vault = &mut ctx.accounts.vault;
vault.total = vault.total.checked_add(amount).ok_or(VaultError::Overflow)?;
emit!(Deposited { amount, vault: vault.key() });
Ok(())
}
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut, seeds = [b"vault"], bump = vault.bump)]
pub vault: Account<'info, VaultState>,
#[account(mut)]
pub depositor: Signer<'info>,
}Lo que esto demuestra:
Context<Deposit>envuelve cuentas yprogram_id- Los argumentos de la instrucción se deserializan después de la validación de cuentas
- Devolver
Result<()>propaga errores personalizados ctx.bumpsexpone los bumps canónicos de las semillas
Análisis Profundo
Campos de Contexto
| Campo | Uso |
|---|---|
ctx.accounts | Cuentas validadas mutables/inmutables |
ctx.program_id | Clave pública del programa actual |
ctx.bumps | Mapa de semillas de bump de las restricciones |
ctx.remaining_accounts | Cuentas adicionales no incluidas en la estructura |
Mantén los manejadores pequeños; delega a funciones de módulo para lógica compleja.
Errores Comunes
- Trabajo pesado en el manejador - Límites de CU excedidos. Solución: Extrae ayudantes; evita deserializaciones redundantes.
- Ignorar
ctx.bumps- Vuelve a buscar los bumps en CPI. Solución: Usactx.bumps.vaultdel nombre de la semilla. - Mutar sin intención de persistir - Olvidaste que la cuenta es
Account<T>. Solución: Los cambios se serializan al soltar si son mutables. - Tipo de
Resultincorrecto - Los manejadores deben devolverResultpara rutas con fallos. Solución: UsaResult<()>o las APIs de retorno de datos. - Usar
remaining_accountsciegamente - Ataques de sustitución de cuentas. Solución: Valida el propietario y el discriminador.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Ayudantes de módulo | Lógica compartida entre manejadores | En línea para programas pequeños |
APIs return_data | Devolver bytes al llamador | La mayoría de las instrucciones usan cuentas para la salida |
| Brazos de coincidencia de instrucciones nativas | Sin Anchor | Ergonomía del Contexto de Anchor |
Preguntas Frecuentes
¿Qué versión de Anchor se asume?
0.32.1 en toda esta sección.
¿Puede un PDA ser un `Signer` en la estructura de cuentas?
No. Usa restricciones de semillas y firma CPI.
¿Dónde se almacena el bump?
En el campo de tu estructura de cuenta, establecido en la inicialización.
¿Cómo derivan los clientes los PDAs?
Usa @solana/kit 7.0.0 con bytes de semilla coincidentes.
¿Qué ID de programa se usa para los PDAs?
La dirección declare_id de tu programa Anchor.
¿Las semillas incluyen el bump?
No en el array de semillas; el bump es un parámetro separado para find_program_address.
¿Cómo depurar fallos de PDA?
Compara las claves registradas; verifica las semillas y el ID del programa en el lado del cliente.
¿Son los PDAs exentos de alquiler?
Sí, cuando contienen datos; financia con el pagador en la inicialización.
¿Puede un PDA firmar múltiples CPIs en una ix?
Sí, con las mismas semillas de firmante para cada CPI.
¿Qué leer a continuación?
Consulta los enlaces relacionados para temas más profundos sobre manejadores.
Relacionado
- Argumentos de Instrucción - entradas tipadas
- Accediendo a Cuentas - detalles de
ctx.accounts - El Módulo
#[program]- macro de módulo
Versiones de Stack: Esta página fue escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, y LiteSVM 0.6.x.