Lectura y escritura de datos de cuenta
Los datos de cuenta residen en un búfer de bytes administrado por el runtime. Los programas piden prestado de forma inmutable o mutable, analizan en tipos, mutan y escriben de vuelta con Borsh o actualizaciones de copia cero.
Receta
let mut data = account.try_borrow_mut_data()?;
let state = State::deserialize(&mut &data[..])?;Cuándo usar esto:
- Actualizar contadores, configuraciones o estado de usuario.
- Leer campos de cuenta de tokens SPL (a través del diseño de spl-token).
- Migrar diseños de cuenta en instrucciones de actualización.
Ejemplo de trabajo
pub fn increment(account: &AccountInfo) -> ProgramResult {
if account.data_len() < State::LEN { return Err(ProgramError::InvalidAccountData); }
let mut data = account.try_borrow_mut_data()?;
let mut state = State::deserialize(&mut &data.as_ref()).map_err(|_| ProgramError::InvalidAccountData)?;
state.count = state.count.checked_add(1).ok_or(ProgramError::InvalidArgument)?;
state.serialize(&mut &mut data.as_mut()).map_err(|_| ProgramError::AccountDataTooSmall)?;
Ok(())
}Lo que esto demuestra:
- Guardia de longitud antes de deserializar.
try_borrow_mut_datapara escrituras.- Mapear errores de serialización a
AccountDataTooSmall.
Análisis profundo
Reglas de préstamo
- Un préstamo mutable O muchos inmutables.
- Soltar préstamos antes de CPI en la misma cuenta.
Actualizaciones parciales
La copia cero permite la mutación de campos sin serialización completa.
Notas de Rust
// Preferir subsecciones &mut [u8] para el discriminador + cuerpo.Errores comunes
- Préstamo a través de CPI - Error/pánico del runtime. Solución: Finalizar el préstamo antes de invocar.
- Diseño obsoleto - Deserializar struct antigua en programa nuevo. Solución: Byte de versión + migración.
- Confusión de cuenta de token - Tratar el diseño del token por separado del estado personalizado. Solución: Usar spl-token pack/unpack.
- Redimensionar sin realloc - La serialización falla si la cuenta es demasiado pequeña. Solución: Instrucción CPI realloc primero.
- Copia cero desalineada - UB en castings incorrectos. Solución: Verificar tamaño y alineación.
Alternativas
| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Actualización de campo bytemuck | Rutas de acceso caliente (contadores) | Cadenas de longitud variable |
Anchor Account::try_from | Propietario/discriminador automático | Nativo |
| Vistas de solo lectura | Pinocchio | Ecosistema |
Preguntas frecuentes
¿try_borrow vs borrow?
Usar variantes try_ en programas - fallar con gracia.
¿Quién puede escribir?
Solo el programa propietario de la cuenta.
¿Leer cuentas de otros?
Sí, si se pasan en la transacción - validar propietario.
¿Datos vacíos?
No inicializado - rechazar o ruta de inicialización.
¿Tamaño máximo de escritura?
Espacio asignado de la cuenta.
¿Transacciones concurrentes?
El runtime serializa por cuenta por transacción.
¿Registrar bytes de datos?
Evitar - filtra información del usuario.
¿Cerrar borra datos?
Cero lamports después de cerrar - cero datos primero.
¿realloc?
Ver artículo de realloc.
¿Rent después de crecer?
Más bytes necesitan más lamports.
¿Leer datos de sysvar?
Usar tipos de sysvar dedicados.
¿Pruebas?
LiteSVM con "fixtures" de cuenta.
Relacionado
- Structs de Borsh - Diseños
- realloc y cuentas en crecimiento - Redimensionar
- Discriminadores de cuenta - Tipado
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.