getMultipleAccounts es el método JSON-RPC de Solana que lee un array acotado de cuentas por pubkey en base58 en una sola solicitud y devuelve un array de entradas de cuenta en el mismo orden que la entrada. Cada elemento es el objeto de cuenta o null cuando la cuenta no existe en el commitment solicitado, y la longitud del array de resultados siempre es igual a la longitud de la entrada, por lo que quienes llaman deben alinear por índice en lugar de filtrar los null. El sobre de respuesta incluye context.slot, que identifica la instantánea contra la que se leyó todo el lote, más un array value. Elegir la codificación jsonParsed o base64 cambia el tamaño del payload y el trabajo de análisis del lado del cliente, y el límite de cuentas por solicitud está documentado como acotado pero varía según el proveedor. Esta guía cubre la semántica del método, un ejemplo ejecutable en Node.js, una tabla de medición reproducible, limitaciones y solución de problemas de alineación desfasada y null inesperados.
El problema de lectura de cuentas en clientes de Solana
Una interfaz de billetera, un indexador o un bot de trading rara vez necesita una sola cuenta. Necesita un conjunto: las cuentas de tokens del usuario, un puñado de cuentas mint, algunas cuentas de estado propiedad de programas y quizás un pagador de comisiones. La implementación ingenua itera sobre las pubkeys y llama a getAccountInfo una vez por cuenta, lo que multiplica la latencia por el número de cuentas y consume una unidad de presupuesto del proveedor por llamada. En una página que se actualiza cada pocos segundos, ese bucle es la diferencia entre una interfaz receptiva y una cola de solicitudes duplicadas. (consulta la referencia de getAccountInfo de Solana)
El método de una sola cuenta está documentado en la referencia de Solana getAccountInfo (https://solana.com/docs/rpc/http/getaccountinfo), y sigue siendo la herramienta correcta cuando realmente necesitas una cuenta. La superficie de lectura por lotes existe porque el caso común es muchas cuentas en un mismo punto en el tiempo. Si todavía estás construyendo el modelo mental de una sola cuenta, comienza con Lectura de cuentas de Solana: getAccountInfo y rent antes de añadir el procesamiento por lotes.
El modelo de costos importa aquí. Cada solicitud JSON-RPC que envías es una unidad de trabajo para tu endpoint, y los proveedores miden solicitudes, no cuentas. Reemplazar un bucle de N llamadas por una sola llamada que lleva N pubkeys cambia tanto el número de viajes de ida y vuelta como la huella en el presupuesto. La medición exacta está documentada por proveedor, así que trata cualquier número específico como dependiente del proveedor y verifícalo con tu plan.
- N llamadas secuenciales a getAccountInfo = N viajes de ida y vuelta y N unidades de presupuesto.
- Una llamada a getMultipleAccounts = un viaje de ida y vuelta que lleva N pubkeys.
- El lote se lee contra un único slot de contexto, lo que es una garantía de consistencia más fuerte que N lecturas independientes.
Qué devuelve getMultipleAccounts y por qué se garantiza el orden
La referencia de Solana getMultipleAccounts (https://solana.com/docs/rpc/http/getmultipleaccounts) documenta el método como aquel que toma un array de pubkeys codificadas en base58 y devuelve un array de entradas de cuenta. El contrato crítico es posicional: el resultado value[i] corresponde a la pubkey de entrada pubkeys[i]. La longitud del array es igual a la longitud de la entrada, y una cuenta faltante se representa como null en su índice en lugar de omitirse.
Ese comportamiento de null en su lugar es la parte que más integraciones hacen mal. Si filtras los null antes de alinear, cada índice después de la primera cuenta faltante se desplaza y adjuntas silenciosamente los datos de la cuenta equivocada a la pubkey equivocada. El patrón seguro es iterar el array de entrada por índice y leer value[i] para cada i, tratando null como un resultado de primera clase.
El sobre de respuesta envuelve el array en un objeto context. El campo context.slot identifica el slot de banco contra el que se leyó el lote, y como todas las cuentas de una llamada comparten ese slot, el lote es una instantánea consistente. Esa es una ventaja significativa sobre N llamadas separadas a getAccountInfo, que pueden aterrizar en slots diferentes y producir una vista fragmentada del estado relacionado.
- value.length === pubkeys.length, siempre.
- value[i] es el objeto de cuenta para pubkeys[i], o null si no se encuentra.
- context.slot es la identidad de la instantánea para todo el lote.
- Nunca descartes los null antes de emparejar los resultados con las entradas.
Elección de codificación: jsonParsed frente a base64
getMultipleAccounts acepta un parámetro de codificación que controla cómo se serializan los datos de la cuenta. base64 devuelve los bytes crudos de la cuenta codificados como una cadena, lo cual es compacto e inequívoco pero requiere que el cliente deserialice. jsonParsed pide al nodo que decodifique diseños de cuenta conocidos, como las cuentas de SPL Token, en JSON estructurado, lo cual es conveniente pero produce payloads más grandes y depende de que el nodo reconozca el diseño del propietario de la cuenta.
El compromiso es tamaño del payload frente a trabajo del lado del cliente. Para un lote de cien cuentas de tokens, jsonParsed puede ser varias veces más grande en la red que base64, y los bytes extra se pagan en cada actualización. Para un lote de cuentas propiedad de programas con diseños personalizados, jsonParsed puede devolver solo los datos crudos de todos modos, así que base64 más tu propio decodificador suele ser la opción más predecible.
La codificación es un parámetro por solicitud, así que puedes mezclar estrategias entre llamadas: usa jsonParsed para una visualización de saldo pequeña orientada a humanos y base64 para un bucle de indexador de alta frecuencia. La referencia del método documenta las codificaciones aceptadas; confirma cuáles habilita tu proveedor, ya que el soporte está documentado pero puede variar según el proveedor.
- base64: payload más pequeño, el cliente deserializa.
- jsonParsed: salida estructurada para diseños reconocidos, payload más grande.
- La codificación es por solicitud, así que distintos puntos de llamada pueden elegir de forma diferente.
getMultipleAccounts frente a getAccountInfo y getProgramAccounts
Las tres superficies de lectura responden a preguntas diferentes. getAccountInfo lee exactamente una cuenta por pubkey. getMultipleAccounts lee un conjunto acotado de cuentas por pubkey en una sola solicitud. getProgramAccounts escanea todas las cuentas propiedad de un programa, opcionalmente filtradas, lo cual es una operación fundamentalmente distinta con características de costo diferentes. El escaneo a nivel de programa y su contraparte en streaming se cubren en getProgramAccounts: stream de cuentas para indexadores.
Elige getMultipleAccounts cuando ya conoces las pubkeys y las quieres en un mismo slot. Elige getProgramAccounts cuando no conoces las pubkeys y necesitas descubrimiento. Elige getAccountInfo cuando necesitas exactamente una cuenta y quieres la llamada más simple posible, o cuando necesitas un commitment por llamada que difiera del resto de tu lote.
Hay una tercera opción que vale la pena nombrar: un lote JSON-RPC 2.0, que envuelve múltiples llamadas a métodos independientes en una sola solicitud de transporte. La especificación JSON-RPC 2.0 (https://www.jsonrpc.org/specification) define este sobre, y es la herramienta correcta cuando necesitas parámetros por llamada o commitment por llamada. Un lote de llamadas a getAccountInfo te da resultados independientes y errores independientes; una llamada a getMultipleAccounts te da un único array ordenado y un único slot de contexto. La mecánica a nivel de transporte se cubre en Mejores prácticas para el procesamiento por lotes JSON-RPC.
- getAccountInfo: una pubkey, una cuenta, la llamada más simple.
- getMultipleAccounts: muchas pubkeys, una solicitud, array ordenado, un slot.
- getProgramAccounts: descubrimiento por propietario del programa, no por pubkey conocida.
- Lote JSON-RPC: múltiples llamadas independientes, parámetros y errores por llamada.
Ejemplo ejecutable en Node.js con @solana/web3.js
El ejemplo siguiente usa @solana/web3.js, que expone getMultipleAccountsInfo en una Connection. Construye un array de pubkeys que mezcla deliberadamente una cuenta existente con una inexistente, llama al método, imprime el slot de contexto y luego empareja los resultados con las entradas por índice. El paso de emparejamiento es la parte que debes copiar al código de producción.
Reemplaza la URL del endpoint con tu propio endpoint RPC. El ejemplo imprime present o null para cada índice para que puedas ver el contrato posicional en acción. Ten en cuenta que la pubkey inexistente es una cadena base58 válida que simplemente no tiene cuenta, que es exactamente el caso que produce un null en lugar de un error.
import { Connection, PublicKey } from '@solana/web3.js';
const connection = new Connection('https://your-solana-rpc-endpoint', 'confirmed');
// A real, well-known account plus a valid-but-nonexistent pubkey.
const existing = new PublicKey('11111111111111111111111111111111');
const missing = new PublicKey('So11111111111111111111111111111111111111112');
const inputs = [existing, missing];
const res = await connection.getMultipleAccountsInfo(inputs);
console.log('context slot:', res.context.slot);
res.value.forEach((account, i) => {
const label = account ? 'present' : 'null';
console.log(`index ${i} ${inputs[i].toBase58()} -> ${label}`);
});
// Safe zip: iterate inputs by index, never filter nulls first.
const zipped = inputs.map((pubkey, i) => ({
pubkey: pubkey.toBase58(),
account: res.value[i] ?? null,
}));
console.log(zipped);Ejemplo ejecutable de JSON-RPC crudo con fetch
Si no usas @solana/web3.js, la misma llamada es un POST JSON-RPC simple. El array params es [pubkeys, options], donde options lleva la codificación y el commitment. La forma de la respuesta es el sobre de resultado JSON-RPC estándar con context y value.
Este ejemplo usa codificación base64 e imprime el slot más un resumen de present/null. Es intencionalmente mínimo para que puedas pegarlo en un script y apuntarlo a cualquier endpoint. La referencia del método documenta el orden exacto de los parámetros; mantén el array de pubkeys primero y el objeto de opciones segundo.
const endpoint = 'https://your-solana-rpc-endpoint';
const body = {
jsonrpc: '2.0',
id: 1,
method: 'getMultipleAccounts',
params: [
[
'11111111111111111111111111111111',
'So11111111111111111111111111111111111111112'
],
{ encoding: 'base64', commitment: 'confirmed' }
]
};
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const json = await response.json();
if (json.error) throw new Error(JSON.stringify(json.error));
const { context, value } = json.result;
console.log('context slot:', context.slot);
value.forEach((account, i) => {
console.log(`index ${i} -> ${account ? 'present' : 'null'}`);
});Medición reproducible: llenar tu propia tabla de resultados
El comportamiento del proveedor, las condiciones de red y los tamaños de cuenta afectan los números reales, así que el enfoque honesto es medir contra tu propio endpoint en lugar de confiar en una cifra publicada. La tabla siguiente es una plantilla. Ejecuta la misma carga de trabajo dos veces: una como un bucle de N llamadas a getAccountInfo, otra como una sola llamada a getMultipleAccounts, y registra los valores observados.
Usa un conjunto fijo de pubkeys y un commitment fijo para que la comparación sea justa. Ejecuta cada variante varias veces y registra la mediana en lugar de una sola muestra, porque la primera llamada después de un arranque en frío no es representativa. Si tu proveedor expone contadores de solicitudes, registra las unidades de presupuesto consumidas además del tiempo de reloj.
- Número de entradas: número de pubkeys en el lote.
- Número de solicitudes: 1 para getMultipleAccounts, N para el bucle.
- Tiempo de reloj del bucle único: mediana entre ejecuciones repetidas.
- Tiempo de reloj de getMultipleAccounts: mediana entre ejecuciones repetidas.
- Null encontrados: recuento de entradas null en el resultado.
- Slot de contexto: el slot reportado para el lote.
Limitaciones y compromisos de la lectura por lotes de cuentas
El límite de cuentas por solicitud está documentado como acotado pero varía según el proveedor, así que un lote que funciona en un endpoint puede ser rechazado en otro. El techo citado comúnmente es del orden de cien pubkeys, pero trátalo como un punto de partida para la verificación, no como una garantía. Si necesitas más cuentas de las que permite el límite, divide en múltiples llamadas y acepta que pueden aterrizar en slots diferentes.
Un argumento malformado hace fallar toda la llamada. Si una pubkey del array no es base58 válida, la solicitud da error en lugar de devolver un null en ese índice, así que valida las entradas antes de enviar. Esto es diferente de una pubkey válida sin cuenta, que produce un null.
Un null significa no encontrado en ese slot, no una cuenta vacía. Una cuenta puede existir en un slot y estar ausente en otro, así que un null es una afirmación sobre el commitment y el slot solicitados, no una propiedad permanente de la pubkey. Los lotes muy grandes también pueden exceder los límites de tamaño de solicitud del proveedor incluso cuando el número de cuentas está dentro de los límites, porque el tamaño del payload depende de la longitud de los datos de la cuenta y de la codificación.
- Límite de cuentas por solicitud: documentado, varía según el proveedor.
- Una pubkey inválida hace fallar toda la llamada.
- null significa no encontrado en ese slot, no una cuenta vacía.
- Los lotes grandes pueden alcanzar límites de tamaño de solicitud independientemente del número de cuentas.
Solución de problemas de alineación desfasada y null inesperados
La alineación desfasada casi siempre proviene de filtrar u ordenar el array de resultados antes de emparejarlo. Si llamas a value.filter(Boolean) y luego indexas en el array filtrado, cada entrada después del primer null queda desalineada. La solución es conservar el array original y leer value[i] para cada índice de entrada, como se muestra en los ejemplos anteriores.
Los null inesperados normalmente significan que la cuenta no existe en el commitment solicitado, o que la pubkey es correcta pero la cuenta fue cerrada. Verifica el slot de contexto y vuelve a leer con un commitment diferente si sospechas de una condición de carrera. Si aparece un null para una cuenta que crees que existe, verifica la codificación de la pubkey y confirma que estás consultando el clúster previsto.
Los errores de límite de tamaño se manifiestan como errores JSON-RPC en lugar de resultados parciales. Si se rechaza un lote, reduce el número de cuentas, cambia de jsonParsed a base64 para reducir el payload, o divide en múltiples llamadas. Para los indexadores que no deben perder slots, combina las lecturas por lotes con detección de huecos como se describe en getBlocks y slots omitidos para indexación sin huecos.
- Desalineación: causada por filtrar u ordenar antes de emparejar.
- null inesperado: verifica commitment, slot, clúster y codificación de la pubkey.
- Error de límite de tamaño: reduce el recuento, cambia la codificación o divide el lote.
Próximos pasos para lecturas por lotes en producción
Empieza reemplazando tu bucle de N llamadas más activo por una sola llamada a getMultipleAccounts, luego mide el cambio con la tabla de resultados anterior. Conserva la ruta de una sola cuenta para los casos que realmente necesitan una cuenta, y conserva una ruta de lote JSON-RPC para los casos que necesitan parámetros por llamada o commitment por llamada.
Para la selección de endpoint y detalles de red, consulta la página de la red Solana. Para una orientación más amplia sobre el uso de RPC de Solana, la guía de la API de Solana (RPC Assistant) cubre endpoints y métodos comunes. Cuando estés listo para dimensionar un plan en función de tu volumen de solicitudes medido, revisa Precios de RPC y las opciones de Servicio de API.
Por último, explora el centro de aprendizaje de OnFinality para guías de integración relacionadas. La superficie de lectura por lotes es una pieza de una estrategia de lectura más amplia que incluye lecturas de una sola cuenta, escaneos de programas e indexación sin huecos.
- Reemplaza los bucles de N llamadas más activos por una sola llamada a getMultipleAccounts.
- Conserva getAccountInfo para lecturas de una sola cuenta.
- Conserva los lotes JSON-RPC para parámetros y errores por llamada.
- Mide antes y después con tu propia tabla de resultados.