Anchor es el framework dominante para escribir programas de Solana en Rust. Se asienta sobre el mismo runtime de Agave que los programas nativos (bytecode SBF, metadatos de cuenta explícitos, unidades de cómputo, CPI), pero genera el pegamento que de otro modo escribirías a mano: discriminadores de instrucciones, dispatch del punto de entrada, comprobaciones declarativas de cuentas, errores tipados, eventos y un IDL que los clientes consumen.
Esta página es el paraguas para anchor-basics: qué es Anchor, cómo el módulo #[program] y las estructuras #[derive(Accounts)] forman la superficie de instrucciones, cómo se organiza un espacio de trabajo, cómo encajan la compilación/despliegue y las pruebas locales, y cómo se compara Anchor con los programas nativos.
Anchor 0.32.1 convierte el desarrollo de programas de Solana en un flujo de trabajo restringido y respaldado por IDL: declare el ID del programa y los manejadores en #[program], declare las cuentas y restricciones en las estructuras Accounts, luego anchor build / anchor test / anchor deploy envían el binario más el esquema del cliente.
Perspicacia: La mayoría de los errores de producción en Solana son errores de validación de cuentas y de esquema de cliente, no errores de lógica de negocio ingeniosos. Anchor falla de forma cerrada ante firmantes faltantes, propietarios incorrectos y semillas de PDA incorrectas, y mantiene a los clientes de TypeScript (y otros) honestos a través del IDL.
Conceptos Clave:declare_id!, #[program], Context<T>, #[derive(Accounts)], restricciones, estado #[account], IDL, Anchor.toml, SBF / .so, nativo vs Anchor.
Cuándo Usar: Construir programas de aplicaciones, superficies administrativas, lógica de escrow y mercados, aplicaciones adyacentes a SPL, y cualquier cosa que se beneficie de clientes tipados en @solana/kit 7.0.0 o la pila TS de Anchor.
Limitaciones/Compromisos: La expansión de macros añade tamaño binario y algo de sobrecarga de CU; las rutas críticas extremas pueden requerir Pinocchio o nativo; todavía debes diseñar tú mismo los layouts, las amenazas y las migraciones.
Temas Relacionados: Ejemplos básicos de Anchor, estructura del proyecto, módulo del programa, estructura de cuentas, flujo de trabajo, compilación y despliegue, Anchor vs nativo.
A nivel de runtime, un programa de Solana todavía implementa aproximadamente process_instruction(program_id, accounts, instruction_data). Anchor no cambia ese contrato. Genera el punto de entrada y desempaqueta los datos de la instrucción en manejadores con nombre y argumentos tipados.
Lo que escribes es un espacio de trabajo: crates de Rust bajo programs/, pruebas de TypeScript (u otro) bajo tests/, y Anchor.toml para el clúster, IDs de programas y scripts. El crate del framework es anchor-lang 0.32.1 (más anchor-spl cuando tocas Token/Associated Token).
La promesa del producto de Anchor es triple:
Valores predeterminados de seguridad - la validación de cuentas se ejecuta antes del cuerpo de tu manejador; las restricciones faltantes generan un error en lugar de confiar silenciosamente en las cuentas del cliente.
Ergonomía - menos código repetitivo para discriminadores, ayudantes de CPI y tipos de cuenta comunes (Signer, Account<T>, Program<T>).
Contrato del cliente - anchor build emite el IDL JSON para que el código fuera de la cadena y los módulos CPI se mantengan alineados con las instrucciones en cadena.
declare_id! codifica la clave pública del programa que espera el binario; debe coincidir con el despliegue (usa anchor keys sync después de que cambien las claves del despliegue).
#[program] marca el módulo cuyas funciones públicas se convierten en instrucciones.
Cada manejador toma Context<SomeAccounts> (y argumentos de instrucción opcionales), devuelve Result<()>, y muta solo a través de campos de cuenta validados.
Los datos de la instrucción no son bytes de formato libre que analizas ad hoc: Anchor deriva discriminadores de 8 bytes y serializa argumentos con Borsh. Los clientes que omiten el IDL (o lo regeneran tarde) fallan de maneras confusas.
La estructura de Cuentas
Cada instrucción nombra una estructura de cuentas con #[derive(Accounts)]. Los tipos de campo y los atributos son el programa de validación.
Antes de que se ejecute initialize, Anchor comprueba los firmantes, la mutabilidad, las semillas de PDA, el ID del programa del sistema y que init asigna y otorga la propiedad correctamente. Account<'info, Counter> se deserializa con el discriminador de cuenta de 8 bytes. Los fallos devuelven errores de Anchor en lugar de escrituras parciales.
Estructura del proyecto (mapa mínimo)
workspace/ Anchor.toml # toolchain, programs.<cluster>, scripts Cargo.toml # workspace members = ["programs/*"] programs/my_program/ Cargo.toml # anchor-lang = "0.32.1" src/lib.rs tests/*.ts target/deploy/*.so # después de compilar target/idl/*.json # después de compilar
Anchor.toml fija qué ID de programa se mapea a qué nombre de clúster. El Cargo.toml raíz es un espacio de trabajo de Rust; cada programa es su propio crate. Las pruebas suelen llamar al programa a través de un proveedor (validador local / Surfpool) utilizando el IDL generado.
Compilación, despliegue y flujo de trabajo en una frase
anchor build compila SBF y regenera el IDL; anchor test despliega localmente y ejecuta pruebas; anchor deploy empuja el .so a un clúster; los clientes y consumidores de CPI deben seguir el nuevo IDL y el ID del programa.
Anchor vs nativo (orientación)
Los programas nativos usan entrypoint!, recorrido manual de cuentas y codecs de cliente mantenidos a mano. Anchor genera esa superficie. Pagas algo de tamaño/CU y ganas restricciones más IDL. Los núcleos de liquidación críticos a veces abandonan Anchor; la mayoría de los programas de productos no deberían empezar de forma nativa "por pureza".
Editar lib.rs (#[program] + Cuentas + estado #[account]) | v anchor build --> target/deploy/*.so + target/idl/*.json | v anchor test --> validador local/Surfpool + pruebas TS | v anchor deploy --> programa actualizable en el clúster | v keys sync / IDL publish --> clientes y consumidores de declare_program!
Ruta de dispatch en cadena
La transacción lista el ID del programa, las cuentas y los datos de la instrucción.
El runtime carga el programa .so e invoca el punto de entrada generado.
Anchor coincide con el discriminador de instrucción de 8 bytes a un manejador.
Anchor deserializa los argumentos y construye Context<T> validando la estructura Accounts.
Tu manejador ejecuta la lógica de negocio y devuelve Ok(()) o un error.
En caso de éxito, las escrituras de datos de cuenta y los cambios de lamport se confirman con la transacción; en caso de error, toda la transacción falla.
Contexto es el traspaso
Context<T> contiene accounts: T, program_id, bumps (para las semillas de PDA descubiertas durante la validación) y las cuentas restantes cuando las usas. Los manejadores no deben volver a analizar las listas de AccountInfo desde cero; deben confiar (y solo extender con require!) lo que las restricciones ya han aplicado.
Las restricciones son el límite de seguridad
Atributos comunes:
Restricción / tipo
Rol
Signer
Firma de transacción presente
mut
Meta de cuenta escribible requerida
init / init_if_needed
Crear (cuidado con esta última)
seeds + bump
Derivación de PDA y comprobación de dirección
has_one
Igualdad de campo (p. ej., autoridad almacenada)
Program<T>
ID de programa conocido (System, Token, …)
constraint = expr
Invariante booleano personalizado
El orden importa para la seguridad de init y CPI; trate el orden de validación como parte del diseño, no como un accidente de la lista de atributos. Las reglas de negocio personalizadas pertenecen a las restricciones o a un require! temprano, no a "comprobaremos más tarde si lo recordamos".
Interacciones de configuración del espacio de trabajo
Desfase del ID del programa: el binario declare_id!, Anchor.toml[programs.*] y la clave del par de despliegue en cadena deben coincidir. Después del despliegue, anchor keys sync reescribe las fuentes/configuración cuando el par de claves es la fuente de verdad.
Desfase del IDL: los cambios en la API pública (nueva ix, campos renombrados, layout de cuenta) requieren reconstrucción y regeneración del cliente. Enviar solo un .so nuevo sin IDL es cómo las dapps llaman a discriminadores incorrectos.
Aislamiento del clúster: localnet, devnet y mainnet-beta son universos de cuentas separados; nunca reutilices una suposición de ID de programa de devnet en clientes de mainnet.
Lado del cliente
Las pruebas y las aplicaciones construyen instrucciones a partir del IDL. @solana/kit 7.0.0 no requiere Anchor específicamente, pero necesita formatos de cableado correctos. La fortaleza de Anchor es producir ese contrato a partir de las mismas macros que generan el programa. Prefiera regenerar clientes tipados en CI cuando el IDL cambie.
Piense en cada función #[program] como un método público versionado. Los discriminadores estables y los órdenes de cuenta estables importan más que los módulos ingeniosos de Rust. Prefiera instrucciones aditivas y layouts de cuenta versionados sobre la reordenación silenciosa de campos.
Cuando cambie el space de la cuenta, planifique instrucciones de realloc o migración; los clientes que tengan layouts antiguos fallarán las comprobaciones de discriminador o deserialización por una buena razón.
Anchor elimina clases enteras de errores (autoridad no firmada, propietario de programa incorrecto en Account<T>, dirección incorrecta del programa del sistema). No inventa tu modelo de amenazas:
¿Quién puede llamar a esta instrucción?
¿Qué cuentas siguen siendo UncheckedAccount y por qué?
¿Son las cuentas de tokens la mint/autoridad esperada?
¿Está init_if_needed creando una superficie de ataque de reinicialización?
¿Se mantienen los objetivos de CPI y los límites de cuentas restantes bajo metadatos adversarios?
La revisión de seguridad todavía se centra en las restricciones, las semillas y los gráficos de CPI, no solo en las matemáticas del manejador.
Un espacio de trabajo puede contener varios crates bajo programs/. Las llamadas entre programas necesitan metadatos de cuenta correctos y, en Anchor 0.32, a menudo declare_program! o tipos compartidos para el llamado. Los límites del framework todavía se componen a través de CPI: un programa de Anchor puede llamar a nativo/Pinocchio si los bytes y las semillas coinciden.
"Anchor es un runtime diferente o una cadena separada." Compila a programas SBF ordinarios en Agave; los validadores no tratan a Anchor de forma especial.
"Las restricciones significan que puedo omitir el diseño de seguridad." Las restricciones aplican lo que declaras. Las suposiciones de confianza no declaradas siguen siendo explotables.
"declare_id! es decorativo." El desajuste con el programa desplegado causa fallos en tiempo de ejecución (DeclaredProgramIdMismatch). Sincronice después de cambios de clave.
"Los manejadores se ejecutan antes de las comprobaciones de cuenta." La validación de la estructura Accounts se ejecuta primero; el manejador asume un Context válido.
"El IDL es documentación opcional." Para los programas de Anchor, el IDL es el contrato del cliente. Trátelo como un artefacto de lanzamiento.
"Nativo es siempre más rápido, así que empiece siempre de forma nativa." A menudo falso para la velocidad del equipo y la seguridad. Mida; por defecto use Anchor para programas de aplicaciones.
"anchor deploy por sí solo actualiza todos los clientes." El despliegue actualiza el bytecode en cadena; las aplicaciones, los indexadores y los módulos CPI necesitan el IDL y el ID del programa coincidentes.
"Cualquier AccountInfo en las cuentas restantes es seguro si la estructura principal es estricta." Las cuentas restantes son una superficie de desvío común; delimítelas y valídalas explícitamente.
Un framework de Rust para programas de Solana que genera dispatch de instrucciones, validación declarativa de cuentas, errores/eventos y un IDL a partir de macros sobre el runtime estándar de Agave.
¿Qué versiones fija este sitio?
Anchor 0.32.1, Rust 1.91.1, Solana CLI 3.0.10, Agave 4.1.1, y @solana/kit 7.0.0 como la pila de cliente de referencia.
¿Qué genera #[program]?
El punto de entrada del programa, la coincidencia del discriminador de instrucción, la deserialización de argumentos y el cableado de cada función pública a su ruta de validación Context<T>.
¿Qué es Context<T>?
El argumento del manejador que contiene las cuentas validadas (T), el ID del programa, las semillas de PDA descubiertas durante la validación y las cuentas restantes opcionales.
¿Qué hace #[derive(Accounts)]?
Construye una lista de cuentas tipada y ejecuta restricciones de nivel de tipo más atributos (signer, mut, owner, seeds, init, expresiones personalizadas) antes de que se ejecute el cuerpo del manejador.
¿Por qué las estructuras de Cuentas usan una vida útil <'info>?
Las referencias a cuentas están vinculadas al ámbito de préstamo de AccountInfo de la instrucción para esa invocación; la vida útil rastrea correctamente ese préstamo de corta duración en Rust.
¿Cuál es la diferencia entre Account<T> y UncheckedAccount?
Account<T> aplica la propiedad del programa y deserializa T con el discriminador de cuenta de Anchor. UncheckedAccount omite estas comprobaciones; debes validar manualmente o estarás expuesto a ataques.
¿Cómo se relaciona la estructura del proyecto con el despliegue?
programs/*/src es el crate en cadena; target/deploy contiene el .so; Anchor.toml mapea los nombres de los programas a las claves públicas por clúster; las pruebas y los clientes consumen target/idl.
¿Qué produce anchor build?
Un objeto compartido SBF bajo target/deploy/ y JSON IDL bajo target/idl/, además de artefactos de clave relacionados para programas desplegables.
¿Cómo debo iterar día a día?
Cambie el código del programa y las cuentas, ejecute anchor build, ejecute anchor test localmente, corrija los fallos, y luego promocione al despliegue en devnet y actualizaciones de cliente antes de mainnet.
¿Cuándo debería elegir nativo en lugar de Anchor?
Cuando los requisitos medidos de CU o tamaño binario, o las preferencias de auditoría/proceso para una validación totalmente manual, superen la productividad del IDL y las macros; a menudo como una extracción de ruta crítica, no una reescritura completa de la aplicación.
¿Pueden los programas de Anchor llamar a programas nativos?
Sí, a través de CPI, cuando los metadatos de cuenta, la propiedad, los layouts de datos y las semillas de firmante de PDA coinciden con lo que espera el llamado.
¿Todavía necesito Solana CLI si uso Anchor CLI?
Sí. Solana CLI 3.0.10 maneja pares de claves, saldos, airdrops, configuración de clúster e inspección de solana program junto con los comandos anchor.