Conceptos básicos del modelo de cuentas
10 ejemplos para empezar con el modelo de cuentas de Solana: 7 básicos y 3 intermedios.
Prerrequisitos
solana config set --url devnet
npm install @solana/kit@7.0.0 @coral-xyz/anchor@0.32.1Anchor 0.32.1 / anchor-lang 0.32.1 para los ejemplos en cadena. La semántica del validador Agave 4.1.1 se aplica en todo momento.
Ejemplos básicos
1. Obtener campos de cuenta sin procesar
Cada cuenta expone los mismos cinco campos principales a través de RPC.
import { createSolanaRpc, address } from "@solana/kit";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const { value } = await rpc.getAccountInfo(address("TU_PUBKEY"), { encoding: "base64" }).send();
console.log({
lamports: value?.lamports,
owner: value?.owner,
executable: value?.executable,
dataLength: value?.data.length,
rentEpoch: value?.rentEpoch,
});lamportses el saldo de SOL;owneres el programa permitido para escribirdataexecutable: truesignifica que la cuenta es un programa desplegado- Las direcciones vacías devuelven
null: aún no existe ninguna cuenta
Relacionado: Anatomía de la cuenta - desglose campo por campo
2. Inspeccionar el tamaño de la cuenta y el alquiler
El tamaño de los datos de la cuenta determina el depósito exento de alquiler.
solana rent 165- La salida muestra los lamports requeridos para la exención de alquiler en ese tamaño de bytes
- Las cuentas de tokens SPL suelen tener 165 bytes
- Siempre financiar hasta el mínimo exento de alquiler en la creación de la cuenta
Relacionado: Alquiler y exención de alquiler - detalles del cálculo
3. Distinguir entre propiedad del sistema y propiedad del programa
El campo owner determina quién puede escribir datos.
const SYSTEM_PROGRAM = "11111111111111111111111111111111";
const TOKEN_PROGRAM = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
// Propiedad del sistema: solo el Programa del Sistema puede mutar (por ejemplo, cuentas de billetera)
// Propiedad del token: el programa SPL Token gestiona los datos de la cuenta de token- Las cuentas de billetera son propiedad del Programa del Sistema
- Las cuentas de tokens SPL son propiedad del Programa de Tokens
- Tu programa es propietario de las cuentas que crea a través de
init
Relacionado: Cuentas del sistema frente a cuentas de programas
4. Crear una cuenta con el Programa del Sistema
La creación de cuentas asigna espacio y transfiere la propiedad.
solana create-account --help
# Normalmente se hace a través de la inicialización del programa o comandos de asignación de la CLI// Anchor maneja esto a través de #[account(init, payer = ..., space = N)]- La creación requiere un pagador para financiar lamports exentos de alquiler
spacees el tamaño del búfer de datos en bytes- El propietario se establece en la creación y solo se puede cambiar a través de programas específicos
Relacionado: Creación y cierre de cuentas
5. Patrón de estado propiedad del programa
Los programas almacenan el estado de la aplicación en cuentas separadas.
#[account]
pub struct Counter {
pub count: u64,
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut)]
pub counter: Account<'info, Counter>,
}- La cuenta
Countercontiene datos; la binaria del programa contiene la lógica Account<'info, Counter>deserializa el búfer de bytes a través de Borsh- Una cuenta por instancia de contador, no una ranura de almacenamiento global
Relacionado: Estado propiedad del programa
6. Forzar la propiedad en las instrucciones
Solo el programa propietario puede escribir; tu programa debe validar los firmantes.
#[derive(Accounts)]
pub struct Update<'info> {
#[account(mut, has_one = authority)]
pub data: Account<'info, MyData>,
pub authority: Signer<'info>,
}has_one = authorityverifica que una pubkey almacenada coincida con el firmante- El firmante debe estar marcado en la lista de cuentas de la transacción
- La falta de validación es la principal fuente de exploits del modelo de cuentas
Relacionado: Propiedad y permisos de cuenta
7. Calcular el espacio de la cuenta para Borsh
Dimensiona el búfer de datos antes de init.
#[account]
pub struct Profile {
pub authority: Pubkey, // 32
pub name: String, // 4 + longitud
}
// espacio = 8 (discriminador) + 32 + (4 + 32) para la longitud máxima del nombre- Anchor agrega automáticamente un discriminador de 8 bytes
StringyVecnecesitan un prefijo de longitud de 4 bytes más el tamaño máximo del contenido- Las cuentas de tamaño insuficiente fallan en la inicialización; las cuentas de tamaño excesivo desperdician alquiler
Relacionado: Cuentas de datos y diseño
Ejemplos intermedios
8. Derivar un PDA para almacenamiento determinista
Los PDA son cuentas sin clave privada, propiedad de tu programa.
#[derive(Accounts)]
pub struct InitVault<'info> {
#[account(
init,
seeds = [b"vault", user.key().as_ref()],
bump,
payer = user,
space = 8 + 8,
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}- Las semillas + el ID del programa producen una dirección determinista fuera de la curva
- El
bumpse almacena para evitar recalcular el bump canónico - El programa firma por el PDA en CPIs a través de
seedsybump
Relacionado: Estado propiedad del programa
9. Cerrar una cuenta y recuperar el alquiler
El cierre devuelve lamports a una cuenta de destino.
#[derive(Accounts)]
pub struct CloseAccount<'info> {
#[account(mut, close = receiver)]
pub data: Account<'info, MyData>,
#[account(mut)]
pub receiver: SystemAccount<'info>,
}- La restricción
closetransfiere todos los lamports areceiver - Los datos se ponen a cero y la cuenta se convierte en propiedad del sistema sin datos
- La recuperación de alquiler es un incentivo común para que los usuarios limpien
Relacionado: Creación y cierre de cuentas
10. Leer datos de cuenta desde RPC
Decodificar el estado en cadena desde un cliente.
import { createSolanaRpc, address } from "@solana/kit";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const account = await rpc
.getAccountInfo(address("COUNTER_ACCOUNT_PUBKEY"), { encoding: "base64" })
.send();
if (account.value) {
const data = Buffer.from(account.value.data[0], "base64");
const discriminator = data.subarray(0, 8);
const count = data.readBigUInt64LE(8);
console.log("Count:", count);
}- RPC sin procesar devuelve bytes codificados en base64: necesitas el diseño para decodificar
- Prefiere el IDL de Anchor y los clientes generados por Codama para la decodificación tipada
- El discriminador son los primeros 8 bytes en las cuentas de Anchor
Relacionado: Cuentas de datos y diseño
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.