Orden de Instrucciones y Dependencias
Los clientes componen múltiples instrucciones de Anchor en una sola transacción. El orden es importante cuando las instrucciones posteriores dependen de cuentas creadas o mutadas por instrucciones anteriores.
Receta
1. create_user (inicializa PDA)
2. create_ata (inicializa cuenta de token)
3. deposit (transfiere tokens)Cuándo usar esto: Cuando diseñas flujos de cliente o documentas pasos de integración.
Ejemplo Funcional
// El cliente envía instrucciones ordenadas en una sola transacción
const tx = await program.methods
.createUser()
.accounts({ /* ... */ })
.preInstructions([/* compute budget si es necesario */])
.rpc();
// O en lote:
// tx = new Transaction().add(ix1, ix2, ix3);// Programa: deposit asume que la PDA de usuario ya está inicializada
#[account(
seeds = [b"user", owner.key().as_ref()],
bump = user.bump,
constraint = user.initialized @ UserError::NotInitialized,
)]
pub user: Account<'info, UserState>,Lo que esto demuestra:
- La inicialización debe preceder al uso en la misma transacción o en una anterior.
- Los lotes atómicos tienen éxito o fallan juntos.
- Las instrucciones idempotentes simplifican los reintentos.
- Documenta el orden requerido en la documentación IDL.
Análisis Profundo
Patrones de Dependencia
- Configuración + acción: Instrucciones separadas de creación y operación.
- Inicialización en la misma transacción: Múltiples instrucciones; la cuenta de la ix0 es visible en la ix1.
- Prefetch: El cliente lee las PDAs fuera de la cadena y las pasa a instrucciones posteriores.
Usa errores explícitos cuando falten los prerrequisitos en lugar de pánicos.
Trampas Comunes
- Depósito antes de la inicialización: Cuenta faltante. Solución: Devuelve el error
NotInitialized. - Asumir atomicidad entre transacciones: Solo una transacción es atómica. Solución: Maneja la finalización parcial en la UI.
- Expiración del blockhash en lotes largos: Reintenta con un blockhash fresco. Solución: Mantén los lotes pequeños.
- Inicialización duplicada en reintento: La segunda transacción falla. Solución: Usa un diseño idempotente o verifica la existencia del lado del cliente.
- Mutabilidad de cuenta incorrecta en el lote: La instrucción posterior falla. Solución: Marca las cuentas como mut en todas las instrucciones que escriben.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Una sola instrucción hace todo | Cliente más simple | Mayor CU por llamada |
| init_if_needed | Menos instrucciones de cliente | Menor seguridad si se usa incorrectamente |
| Transacciones versionadas con ALTs | Muchas cuentas | Transacciones heredadas simples |
Preguntas Frecuentes
¿Qué versión de Anchor se asume?
0.32.1 en toda esta sección.
¿Puede una 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 las PDAs?
Usa @solana/kit 7.0.0 con bytes de semilla coincidentes.
¿Qué ID de programa se usa para las 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 del lado del cliente.
¿Las PDAs están exentas de alquiler?
Sí, cuando almacenan datos; financia con el pagador en la inicialización.
¿Puede una PDA firmar múltiples CPIs en una instrucción?
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 ordenamiento.
Relacionados
- init & init_if_needed - creación
- Ensamblaje de Transacciones - transacciones de cliente
- Construcción de Mensajes de Transacción - @solana/kit
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.