Como discutimos en el tutorial anterior, el punto de entrada (entrypoint) es la “puerta principal” de tu programa de Solana y maneja todas las instrucciones entrantes al programa.
En este tutorial, aprenderemos cómo leer las cuentas pasadas a nuestro programa nativo de Solana en Rust a través del punto de entrada.
En Anchor, defines las cuentas que espera tu programa usando la macro #[derive(Accounts)]:
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = user, space = 8 + 32)]
pub data_account: Account<'info, MyData>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[account]
pub struct MyData {
pub value: u64,
}
Luego accedes a esas cuentas en tu manejador de instrucciones a través del Context:
#[program]
pub mod my_program {
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// other function logic
ctx.accounts.data_account.value = 100;
Ok(())
}
}
Anchor maneja la validación de cuentas y proporciona acceso tipado a través de Context. En Rust nativo, trabajas directamente con el slice sin procesar de accounts que se pasa a tu función procesadora de instrucciones (vimos esto en el tutorial anterior).
Si necesitas un repaso sobre las cuentas de Solana, consulta Initializing Accounts in Solana and Anchor y Solana Counter Program.
Construyendo el Programa en Rust
Vamos a construir un programa que lea y registre en el log las cuentas pasadas a la función procesadora de instrucciones.
Primero, configura el proyecto:
mkdir solana-storage
cd solana-storage
cargo init --lib solana-storage
Actualiza tu Cargo.toml a lo siguiente:
[package]
name = "solana-storage"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
[dependencies]
solana-program = "3.0.0"
borsh = "0.10"
Hemos añadido borsh = "0.10" para futuros tutoriales donde serializaremos los datos de las cuentas.
Leyendo Cuentas en la Función del Punto de Entrada
Reemplaza el código en src/lib.rs con lo siguiente. Este programa itera sobre cada cuenta proporcionada y registra su clave pública, saldo en lamports, propietario, longitud de los datos y si la cuenta es ejecutable, escribible o un firmante. Accede a estas cuentas a través del parámetro accounts pasado a process_instruction, el cual es un arreglo de structs AccountInfo. AccountInfo es el tipo nativo de Solana utilizado para representar cuentas on-chain. Para evitar registrar grandes cantidades de datos, el programa solo imprime los primeros 8 bytes de los datos de cada cuenta como una vista previa de lo que está almacenado.
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
msg,
pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
msg!("Storage Program: Examining {} accounts", accounts.len());
*// Create an iterator over accounts to safely access each account*
let accounts_iter = &mut accounts.iter();
*// Loop through each account and log its metadata*
for (index, account) in accounts_iter.enumerate() {
msg!("Account {}: {}", index, account.key);
msg!("Lamports: {}", account.lamports());
msg!("Owner: {}", account.owner);
msg!("Data length: {} bytes", account.data_len());
msg!("Executable: {}", account.executable);
msg!("Writable: {}", account.is_writable);
msg!("Is signer: {}", account.is_signer);
*// Log only the first 8 bytes to avoid overwhelming the logs*
if account.data_len() > 0 {
let data = account.try_borrow_data()?;
// Take the smaller value between 8 and data.len() so we never slice past the buffer.
// This caps the preview to at most 8 bytes while staying within bounds.
let preview_len = std::cmp::min(8, data.len());
msg!("First {} bytes: {:?}", preview_len, &data[..preview_len]);
} else {
msg!("No data stored");
}
msg!(""); // Empty line for readability
}
Ok(())
}
En nuestros tutoriales anteriores basados en Anchor, hemos utilizado este tipo en contextos de validación de cuentas. En los programas nativos, AccountInfo nos da acceso a todos los metadatos de la cuenta que mantiene Solana, incluyendo la clave pública de la cuenta, lamports (saldo), programa propietario, campo de datos, y banderas como si es ejecutable, escribible o un firmante.
Algunos conceptos clave en este código se destacan en el diagrama a continuación:

accounts.iter(): Crea un iterador sobre el slice deaccountsaccount.try_borrow_data()?: Devuelve una referencia de solo lectura al campo de datos de la cuenta. Usamostry_borrow_data()para tomar prestados de forma segura los datos de la cuenta. Devuelve un error si los datos ya han sido tomados prestados de forma mutable.
Cuando construyes una transacción desde el cliente y especificas las cuentas en el arreglo keys:
const ix = new TransactionInstruction({
keys: [
{ pubkey: payer.publicKey, isSigner: true, isWritable: false },
],
programId: PROGRAM_ID,
data: Buffer.alloc(0),
});
todas las cuentas especificadas se pasan a la función process_instruction de tu programa como el parámetro accounts. Así es como tu programa recibe y puede inspeccionar cualquier cuenta con la que el cliente quiera que trabaje, ya sean firmantes, cuentas escribibles, o simplemente cuentas de las que necesitas leer.
Ahora compila y despliega el programa:
cargo build-sbf
solana-test-validator # in another terminal
solana program deploy target/deploy/solana_storage_tutorial.so

Copia el ID del programa, lo usaremos cuando probemos el programa.
Después de desplegar el programa en el validador local de Solana, ahora estamos listos para probar nuestro programa.
Probando la Inspección de Cuentas
Vamos a crear un cliente que pase múltiples cuentas a nuestro programa y registre sus metadatos.
Configura el entorno del cliente desde el directorio raíz de nuestro proyecto:
mkdir client && cd client
npm init -y
npm install @solana/web3.js typescript ts-node @types/node
Actualiza client/package.json:
{
"scripts": {
"test": "ts-node client.ts"
}
}
Crea client/tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"types": ["node"]
},
"include": ["*.ts"]
}
Ahora crea client/client.ts y añade el siguiente código. En este cliente, nosotros:
- Importamos las dependencias necesarias de
@solana/web3.js - Creamos una función
testAccountInspectionque:- Crea dos cuentas keypair (
payeryemptyAccount) - Financia la cuenta payer con SOL
- Pasa estas cuentas, incluyendo el system program, a nuestro programa para leer y registrar sus metadatos
- Crea dos cuentas keypair (
import {
Connection,
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
sendAndConfirmTransaction,
} from '@solana/web3.js';
const PROGRAM_ID = new PublicKey('YOUR_PROGRAM_ID_HERE');// Replace with your actual program IDconst connection = new Connection('http://localhost:8899', 'confirmed');
async function testAccountInspection() {
console.log('Testing Account Inspection\n');
// Create accounts to inspect
const payer = Keypair.generate();
const emptyAccount = Keypair.generate();
// Fund the payer account
console.log('Funding accounts...');
await connection.requestAirdrop(payer.publicKey, LAMPORTS_PER_SOL);
// Wait for airdrops
await new Promise(resolve => setTimeout(resolve, 2000));
console.log(`Payer: ${payer.publicKey.toString()}`);
console.log(`Empty Account: ${emptyAccount.publicKey.toString()}\n`);
// Create instruction with multiple accounts
const instruction = new TransactionInstruction({
keys: [
{ pubkey: payer.publicKey, isSigner: true, isWritable: false },
{ pubkey: emptyAccount.publicKey, isSigner: false, isWritable: false },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
],
programId: PROGRAM_ID,
data: Buffer.alloc(0),
});
const transaction = new Transaction().add(instruction);
console.log('Sending transaction with 3 accounts for inspection...');
const signature = await sendAndConfirmTransaction(connection, transaction, [payer]);
console.log(`Transaction confirmed: ${signature}`);
console.log('Check the logs to see detailed account information!');
console.log('Run: solana logs');
}
testAccountInspection().catch(console.error);
Actualiza la variable PROGRAM_ID con tu ID de programa.
Antes de ejecutar la prueba, asegúrate de que tu validador local de Solana esté en ejecución y que el programa se haya desplegado en él.
Ahora ejecuta la prueba:
cd client
npm run test
Se ejecuta exitosamente.

En tu terminal de solana logs, deberías ver información detallada para cada cuenta, incluyendo saldos, propietarios y metadatos:

Este artículo es parte de una serie de tutoriales sobre desarrollo en Solana.