El Módulo #[program]
La macro de atributo #[program] genera el punto de entrada de Solana, la distribución de instrucciones y las comprobaciones de discriminador. Tus funciones públicas se convierten en instrucciones en la cadena.
Receta
#[program]
pub mod my_program {
use super::*;
pub fn initialize(ctx: Context<Initialize>, amount: u64) -> Result<()> {
ctx.accounts.config.amount = amount;
Ok(())
}
}Cuándo usar esto: Cuando agregas o renombras una instrucción expuesta a los clientes.
Ejemplo Funcional
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod escrow {
use super::*;
pub fn initialize(ctx: Context<Initialize>, amount: u64) -> Result<()> {
let escrow = &mut ctx.accounts.escrow;
escrow.amount = amount;
escrow.authority = ctx.accounts.authority.key();
Ok(())
}
pub fn release(ctx: Context<Release>) -> Result<()> {
require!(ctx.accounts.authority.key() == ctx.accounts.escrow.authority, EscrowError::Unauthorized);
// Lógica de transferencia...
Ok(())
}
}
#[account]
pub struct Escrow {
pub amount: u64,
pub authority: Pubkey,
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = authority, space = 8 + Escrow::INIT_SPACE)]
pub escrow: Account<'info, Escrow>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Release<'info> {
#[account(mut, has_one = authority)]
pub escrow: Account<'info, Escrow>,
pub authority: Signer<'info>,
}Lo que esto demuestra:
- El nombre del módulo se convierte en el espacio de nombres del módulo del programa en los clientes.
- Cada
pub fnes una instrucción con un discriminador único. - Las estructuras de cuentas son tipos
#[derive(Accounts)]separados. - Devuelve
Result<()>para instrucciones falibles.
Análisis Profundo
Cómo Funciona
- Anchor hashea el nombre de la instrucción a un discriminador de 8 bytes que se antepone a los datos de la instrucción.
- El despachador generado deserializa las cuentas en tu struct
Context<T>. - Las funciones privadas dentro del módulo no se exponen como instrucciones.
use super::*;trae las estructuras de cuentas y los tipos al ámbito.
Firmas de Controladores
| Parte | Rol |
|---|---|
Context<T> | Cuentas validadas para esta instrucción |
| Argumentos adicionales | Datos de instrucción deserializados por Borsh |
Result<()> | Éxito o error de programa personalizado |
Errores Comunes
- Controlador llamado
init- Entra en conflicto con patrones reservados en algunas herramientas. Solución: Usainitializeen su lugar. - Struct de cuenta dentro de
#[program]- La macro no puede encontrar tipos de forma fiable. Solución: Define#[derive(Accounts)]en la raíz del módulo. - Falta
use super::*- Los tipos no están en el ámbito dentro del módulo. Solución: Agrega la importación al principio del módulo del programa. Pub fncon tipoContextincorrecto - El despachador pasa una disposición de cuenta incorrecta. Solución: Haz coincidir el nombre de la struct conContext<StructName>.- Devolver algo que no es
Result- Solo los patronesResulty de retorno de datos compilan para los controladores. Solución: UsaResult<()>a menos que devuelvas datos explícitamente.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
entrypoint! nativo + match | Tamaño mínimo del binario | Quieres validación declarativa de cuentas |
| Despacho Pinocchio | Menor sobrecarga de CU | Necesitas IDL y macros de Anchor |
Múltiples módulos #[program] | No soportado en un solo crate | Dividir en crates de programa separados |
Preguntas Frecuentes
¿Qué versión de Anchor utiliza este sitio?
0.32.1 para anchor-lang, Anchor CLI y ejemplos en esta sección.
¿Necesito Solana CLI además de Anchor?
Sí. Solana CLI 3.0.10 maneja pares de claves, airdrops e inspección de solana program.
¿Dónde vive la IDL después de la compilación?
target/idl/<program>.json en tu espacio de trabajo.
¿Puedo mezclar `UncheckedAccount` con `Signer`?
Sí, pero cada campo no verificado necesita restricciones explícitas o comprobaciones en el controlador.
¿Cómo pruebo sin devnet?
Usa anchor test con Surfpool 0.12.0 o LiteSVM 0.6.x en CI.
¿Qué es el prefijo de 8 bytes en los datos de la cuenta?
Discriminador de cuenta de Anchor; no lo elimines al dimensionar space.
¿Debo confirmar la IDL generada?
Sí, o publica la IDL en la cadena para que los clientes tengan una fuente canónica.
¿Cómo depuro fallos de restricciones?
Ejecuta con logs; Anchor imprime el nombre de la restricción y el índice de la cuenta.
¿Anchor funciona en Agave 4.1.1?
Sí. Esta pila se dirige a validadores Agave con Solana CLI 3.0.10.
¿Qué debo leer a continuación en esta sección?
Consulta los artículos hermanos en Relacionados para temas más profundos sobre el módulo del programa.
Relacionado
- Controladores de Instrucciones - Contexto y firmas
- La Struct de Cuentas - structs de validación
- Compilación y Despliegue - salida de compilación
Versiones de la pila: 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.