Manejo de Errores On-Chain
Los programas comunican fallos a través de ProgramResult (Result<(), ProgramError>) o enums de error personalizados mapeados a códigos. Los clientes decodifican estos códigos off-chain para la experiencia de usuario y la depuración.
Receta
use solana_program::program_error::ProgramError;
fn require_init(data_len: usize, need: usize) -> Result<(), ProgramError> {
if data_len < need {
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}Cuándo usar esto:
- Reemplazar
paniccon fallos de instrucción recuperables. - Definir errores específicos del dominio (deslizamiento, expirado, no autorizado).
- Propagar errores de ayudantes con
?.
Ejemplo Funcional
use solana_program::program_error::ProgramError;
#[repr(u32)]
pub enum VaultError {
InsufficientFunds = 6000,
Unauthorized = 6001,
}
impl From<VaultError> for ProgramError {
fn from(e: VaultError) -> Self {
ProgramError::Custom(e as u32)
}
}
pub fn withdraw(amount: u64, balance: u64) -> Result<(), ProgramError> {
if amount > balance {
return Err(VaultError::InsufficientFunds.into());
}
Ok(())
}Qué demuestra esto:
- Los errores personalizados usan
ProgramError::Custom(code). - La implementación
Fromhabilita?en los manejadores de instrucciones. - Reservar rangos de códigos por programa para evitar colisiones con Anchor.
Análisis Profundo
Capas de Error
| Capa | Tipo |
|---|---|
| Runtime | ProgramError::InvalidAccountData |
| App | ProgramError::Custom(u32) |
| Anchor | Macro de atributo error_code |
Mapeo Off-Chain
- La IDL de Anchor incrusta nombres de error.
- Los programas nativos documentan códigos en README o en el JSON de la IDL.
Notas de Rust
type VaultResult<T> = Result<T, ProgramError>;Errores Comunes
panicenexpect- Aborta sin un código personalizado. Solución: DevolverErrcon una variante explícita.- Colisión de códigos - 6000 puede colisionar con otros programas en los mismos logs de transacciones. Solución: Nombrar códigos en espacio de nombres; documentar por programa.
- Fugas de detalles internos - Los logs detallados revelan pistas para exploits. Solución: Registrar un mensaje genérico públicamente; detallar en simulación privada.
- Ignorar errores de CPI - Se debe propagar el
Resultdeinvoke. Solución: Usar?o mapear a tu enum. - Demasiadas variantes - Los enums de error grandes siguen siendo baratos, pero mantén actualizado el mapeo del cliente. Solución: Versionar la IDL junto con el programa.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
Macro error! de Anchor | Exportación automática de IDL | Compilaciones que no son de Anchor |
Solo utilidades integradas de ProgramError | Códigos mínimos | Experiencia de usuario del producto |
| Eventos para rutas de éxito | Observabilidad enriquecida | No es un sustituto de los errores |
Preguntas Frecuentes
¿Qué es `ProgramResult`?
Alias para Result<(), ProgramError>.
¿Puedo devolver datos en caso de error?
No, la instrucción fallida revierte todos los cambios.
¿Desplazamiento de error de Anchor?
Anchor añade un desplazamiento de 6000+ para códigos personalizados en 0.32.x.
¿`thiserror` on-chain?
Funciona si no se habilitan características solo de std.
¿Registrar dentro de la ruta de error?
Permitido pero cuesta CUs - mantenerlo corto.
¿Decodificación del cliente?
Emparejar el código personalizado con el enum off-chain.
¿`InvalidAccountData` vs `Custom`?
Las utilidades integradas son portátiles; las personalizadas necesitan la IDL del programa.
¿`Result` en ayudantes?
Sí - propagar con ? en el manejador de instrucciones.
¿Macro `assert!`?
Evitar - usar retornos explícitos.
¿Múltiples errores en una transacción?
La primera instrucción fallida falla toda la transacción (a menos que se maneje).
¿Errores de simulación?
Los mismos códigos que en la ejecución on-chain.
¿Errores en CPI?
Propagar o mapear deliberadamente - no ignorar.
Relacionado
- Conceptos Básicos de Manejo de Errores - Introducción a la sección
- Enums de Error Personalizados - Códigos compatibles con IDL
- Depuración de Transacciones Fallidas - Lectura de fallos
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.