init & init_if_needed
init crea una nueva cuenta en la misma instrucción. init_if_needed crea solo cuando falta, lo que introduce el riesgo de reinicialización si las restricciones son débiles.
Busca en todas las páginas de la documentación
init crea una nueva cuenta en la misma instrucción. init_if_needed crea solo cuando falta, lo que introduce el riesgo de reinicialización si las restricciones son débiles.
#[account(
init,
payer = payer,
space = 8 + MyAccount::INIT_SPACE,
seeds = [b"vault", user.key().as_ref()],
bump
)]
pub vault: Account<'info, Vault>,Cuándo usar esto: Una instrucción debe asignar estado propiedad del programa por primera vez.
#[derive(Accounts)]
pub struct CreateProfile<'info> {
#[account(
init,
payer = user,
space = 8 + Profile::INIT_SPACE,
seeds = [b"profile", user.key().as_ref()],
bump
)]
pub profile: Account<'info, Profile>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}init_if_needed está restringido detrás de una característica de cargo. Sin ella, la macro falla al compilar con un error que te indica que la habilites:
[dependencies]
anchor-lang = { version = "0.32.1", features = ["init-if-needed"] }// init_if_needed: solo cuando es idempotente y seguro
#[account(
init_if_needed,
payer = payer,
space = 8 + Stats::INIT_SPACE,
seeds = [b"stats"],
bump,
)]
pub stats: Account<'info, Stats>,Lo que esto demuestra:
init falla si la cuenta ya existepayer financia lamports exentos de alquilerspace incluye el discriminador de 8 bytesinit_if_needed puede omitir la creación cuando la cuenta existeinit_if_needed nunca recrea una cuenta existente, por lo que el cuerpo de tu manejador aún se ejecuta contra el estado en vivo. Anchor ejecuta la ruta completa Account<T> en la cuenta existente (propietario + discriminador de 8 bytes + Borsh) y revalida los atributos declarados como space, owner y token::authority incluso cuando se omite la creación, por lo que se rechazan datos basura arbitrarios.
El ataque real de reinicialización es diferente: si el cuerpo del manejador escribe incondicionalmente valores predeterminados (ctx.accounts.stats.owner = signer.key();), una segunda llamada restablece una cuenta legítima y ya poblada. Protege con un campo initialized: bool almacenado / campo de versión, o constraint = stats.authority == authority.key(), o divide la creación y la actualización en dos instrucciones.
INIT_SPACE o space = 8 + ....init o constraint estricto en el estado existente.Program<System>.#[account(mut)].init_if_needed solo con salvaguardias sólidas.
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Instrucción de creación separada | Ciclo de vida claro | Experiencia de configuración única |
| CPI al programa del sistema manualmente | Programas nativos | Macros init de Anchor |
| init_if_needed + constraint | Incorporación idempotente | Bóvedas de alta seguridad |
0.32.1 para anchor-lang, Anchor CLI y ejemplos en esta sección.
Sí. Solana CLI 3.0.10 maneja pares de claves, airdrops e inspección de solana program.
target/idl/<program>.json en tu espacio de trabajo.
Sí, pero cada campo no verificado necesita restricciones explícitas o verificaciones del manejador.
Usa anchor test con Surfpool 0.12.0 o LiteSVM 0.6.x en CI.
Discriminador de cuenta de Anchor; no lo elimines al dimensionar space.
Sí, o publica el IDL en la cadena para que los clientes tengan una fuente canónica.
Ejecuta con registros; Anchor imprime el nombre de la restricción y el índice de la cuenta.
Sí. Esta pila se dirige a validadores Agave con Solana CLI 3.0.10.
Consulta los artículos hermanos vinculados en Relacionados para temas más profundos sobre init.
Versiones de la pila: Esta página se escribió 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.
Revisado por Chris St. John·Última actualización: 19 jul 2026