Solana Account Archive: consultando o estado de contas em qualquer slot
Autor: Alchemy

O Account Archive responde getAccountInfo para qualquer conta Solana em qualquer slot histórico (com exceção de vote accounts e sysvars por slot), com uma janela de cobertura histórica profunda e sempre crescente, que nunca é podada. Use o parâmetro slot para ler o estado em um ponto no tempo, ou lastUpdateBeforeSlot / firstUpdateAfterSlot para percorrer o histórico de atualizações de uma conta. As leituras são servidas com latência mediana na casa dos microssegundos.
Solana só se lembra do presente
Eis um detalhe sobre a Solana que surpreende até builders experientes: um validator armazena exatamente uma cópia de cada conta, a mais recente. Cada escrita sobrescreve o estado anterior no lugar, e assim, no momento em que uma conta é tocada, o que quer que ela fosse antes desaparece. Mesmo para um slot cujo bloco completo o node ainda possui, o estado da conta naquele slot não existe mais em lugar nenhum na máquina.
Isso é uma característica, não um defeito. É parte do motivo pelo qual a Solana é rápida. Mas significa que uma classe inteira de perguntas bastante razoáveis não tem resposta, como:
- Debugging: "Nossa liquidação disparou no slot 285.401.337. Qual era a conta de preço do oracle exatamente naquele slot?"
- Backtesting: "Reconstrua as reservas desse pool em cada ponto dos últimos seis meses."
- Auditorias: "Prove o que essa token account continha em 3 de março."
- Recuperação: "Nosso indexer ficou fora do ar por quatro horas. Reconstrua exatamente as transições de estado que perdemos."
Você pode pensar que getBlock cobre isso, mas não cobre. Ele retorna as transações de um slot passado e seus saldos pré/pós, não os dados da conta. Para a maioria das aplicações, o estado que importa vive nos bytes de dados: o order book, o price feed, a posição, ou a configuração.
O Solana Account Archive traz o histórico completo de volta. Ele responde getAccountInfo para qualquer conta em qualquer slot desde julho de 2025, usando os mesmos formatos de requisição e resposta que você já usa. Duas coisas o diferenciam. O archive nunca poda dados, então a janela consultável só cresce com o tempo. E ele ignora a própria contabilidade interna por slot da chain (vote accounts e um punhado de sysvars que são reescritas a cada slot), já que isso é ruído, não histórico útil para quem constrói aplicações.
A API: getAccountInfo, estendido
Deliberadamente não inventamos um novo método. O archive fala JSON-RPC padrão e implementa getAccountInfo com todas as opções de configuração que você já conhece: encoding (base64, base58, base64+zstd, jsonParsed), commitment, dataSlice, e minContextSlot, mais três novos parâmetros mutuamente exclusivos:
Esses três também são mutuamente exclusivos com minContextSlot; combiná-lo com qualquer um deles é rejeitado. Omita os três e você obtém um getAccountInfo normal, de estado mais recente; o archive é um superconjunto drop-in. Aqui está uma leitura completa em um ponto no tempo, o estado de uma token account no slot 400.000.000:
curl $ARCHIVE_URL -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getAccountInfo",
"params": [
"3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa",
{ "encoding": "jsonParsed", "slot": 400000000 }
]
}'A resposta segue o formato padrão de getAccountInfo:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"context": { "apiVersion": "4.1.0", "slot": 400000000 },
"value": {
"lamports": 2040821,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"data": {
"program": "spl-token",
"parsed": {
"info": {
"isNative": false,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"owner": "7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE",
"state": "initialized",
"tokenAmount": {
"amount": "1056153754430274",
"decimals": 6,
"uiAmount": 1056153754.430274,
"uiAmountString": "1056153754.430274"
}
},
"type": "account"
},
"space": 165
},
"executable": false,
"rentEpoch": 18446744073709551615,
"space": 165
}
}
}Repare na semântica: slot: S significa o estado no S. Se a conta foi escrita pela última vez no slot S - 40,000 e não foi tocada desde então, você recebe essa escrita, exatamente o que qualquer programa executando no slot S teria visto. E jsonParsed também funciona em estado histórico: os mesmos decoders que um node RPC padrão usa são aplicados aos bytes históricos, então uma token account do início da janela de cobertura volta decodificada, não opaca.
Um iterador sobre o histórico de uma conta
lastUpdateBeforeSlot e firstUpdateAfterSlot transformam o archive em um iterador sobre cada transição de estado de uma conta.
lastUpdateBeforeSlot retorna o slot real da escrita que encontrou em context.slot, então cada resposta é o cursor para a próxima requisição:
# Walk every state transition of an account, newest to oldest.
cursor = current_slot + 1
while True:
try:
result = rpc("getAccountInfo", [pubkey, {"lastUpdateBeforeSlot": cursor}])
except RpcError as e:
if e.code == -32020: # walked past the edge of coverage; done
break
raise
slot = result["context"]["slot"] # the slot this write landed at
handle(slot, result["value"]) # value is null if this write closed the account
cursor = slot # strictly-before: no overlap, no gapsO percurso tem exatamente um ponto de parada: o erro -32020, que significa que o cursor passou da borda da cobertura do archive. Um valor null ao longo do caminho significa o que sempre significa em getAccountInfo: a conta não existia naquele slot — aqui, porque a escrita em context.slot a excluiu. Devolva esse slot como cursor e o percurso continua através da vida anterior da conta.
firstUpdateAfterSlot faz o inverso: em vez de retroceder no tempo, avança, retornando a próxima escrita estritamente depois de um determinado slot. É ideal para um indexer que está se atualizando a partir de um slot conhecido e quer todos os estados intermediários, não apenas o mais recente.
Entre os dois, você pode percorrer todo o ciclo de vida de uma conta: cada mudança de saldo, cada mutação de dados, cada mudança de ownership, com o slot exato em que cada uma ocorreu.
Registrando novas escritas conforme acontecem
Registrar o estado daqui para frente é a parte fácil. O archive escuta a rede através de um stream Geyser e registra escritas de contas conforme acontecem, com duas regras que mantêm o registro confiável:
Somente slots finalizados entram no archive. A Solana sofre forks constantemente na ponta, e um bloco que parece real por alguns segundos pode simplesmente desaparecer. O archive retém as atualizações de cada slot até que a rede o finalize, de modo que o registro permanente contenha apenas o que de fato aconteceu.
Nada se perde silenciosamente. Cada bloco da Solana nomeia seu parent, então qualquer bloco que o stream perca (uma falha momentânea, uma reconexão, um deploy de serviço) é detectado imediatamente e preenchido retroativamente.
A camada de armazenamento por trás disso é uma história à parte. O que importa aqui é o resultado: leituras em um ponto no tempo são rápidas o suficiente para ficar num hot path, com latência mediana na casa dos microssegundos (medida na nossa camada de serviço interna).
Reconstruindo o último ano
Ingerir dados a partir de hoje em diante resulta em um archive útil no ano que vem. Nós queríamos o ano passado também, o que significa reconstruir o estado das contas para dezenas de milhões de slots que já haviam acontecido, em uma chain que não guarda histórico nenhum. E é muita história: a Solana produz um bloco a cada ~400 ms, cerca de 216.000 slots por dia. Ao longo de um ano, isso são ~78 milhões de slots, centenas de bilhões de atualizações de contas, e mais de um petabyte de dados brutos de contas, cada slot carregando milhares de escritas de contas com o payload de dados completo anexado.
Por que "simplesmente parsear as transações" não funciona
Há um atalho tentador: buscar blocos históricos e decodificar o que cada transação fez a cada conta. Ele falha por um motivo fundamental que vale internalizar: uma transação na Solana não é a descrição de uma mudança de estado; é uma invocação de programa.
O que de fato acontece a uma conta depende da execução do programa: CPIs se ramificando para outros programas, sysvars lidas em pleno voo, medição de compute, a semântica precisa do runtime naquele slot. O bloco registra quais contas uma transação tocou e como os saldos se moveram, mas os bytes de dados, a parte que você realmente quer, só são determinados executando o código.
Há apenas uma forma fiel de saber o que uma transação fez a uma conta: executá-la, com o runtime real, contra o estado real sobre o qual ela foi executada.
Replay: rodando a chain de novo
Então é isso que fazemos. O pipeline de backfill é, em essência, um validator que revive a história:
- Inicializar a partir de um snapshot confiável. A Solana Foundation mantém archives públicos de snapshots históricos: capturas completas de cada conta em um dado slot. Carregar o snapshot no slot
Anos dá o estado completo e canônico de várias centenas de milhões de contas naquele momento. - Replay de cada bloco para frente. A partir de
A + 1, cada bloco histórico roda através do runtime real do validator: execução real, não simulação, não parsing de logs. Cada transação executa; as escritas de contas que o runtime produz são capturadas e indexadas, slot por slot. - Parar no próximo snapshot e provar. Esta é a etapa que torna tudo confiável. Quando o replay chega ao slot
B, onde existe o próximo snapshot canônico, comparamos nosso estado final replayado contra ele, incluindo o accounts lattice hash: um compromisso criptográfico sobre todo o conjunto de contas que a própria rede computa e sobre o qual concorda. Se um único byte de uma única conta divergir em qualquer ponto do intervalo, os hashes não vão bater e o intervalo é rejeitado. Não assumimos que o replay está correto; todo intervalo de backfill é checado contra a verdade do consenso antes de ser confiado.
Blocos antigos precisam do runtime de sua época
Aqui está a dificuldade que torna o replay genuinamente difícil: a semântica de execução da Solana é versionada no tempo. Feature gates ativam em épocas específicas, regras de compute budget mudam, syscalls são adicionadas, comportamentos de edge-case são corrigidos. Uma transação de doze meses atrás precisa ser replayada por um runtime que se comporte exatamente como o cluster se comportava naquele slot. Replay-la com o validator de hoje e a etapa 3 vai te avisar, bem claramente, que você fabricou uma história que nunca aconteceu.
Na prática, a frota de backfill roda diversas linhagens de validator fixadas, cada uma responsável pela época que consegue reproduzir fielmente, com o trabalho dividido em blocos ao longo das fronteiras de epoch, de forma que cada bloco comece e termine em um snapshot verificável. Estender o archive ainda mais para trás é, em grande parte, uma questão de montar o runtime da época correta e pagar o custo computacional do replay. E como cada bloco alinhado a epoch é independente, o histórico é perfeitamente paralelizável; fazer o backfill de um ano é basicamente uma questão de quantos workers de replay você roda ao mesmo tempo.
Confiança, continuamente verificada
O backfill verificado por hash cobre o passado; uma preocupação separada é se o caminho de serving continua honesto em produção. Por isso, um watchdog independente cruza continuamente as respostas do archive contra nodes RPC ao vivo, através da mesma API pública que você usaria. Correção é primordial para nós, e por isso ela é reverificada a cada minuto em que o serviço roda. Uma abordagem em múltiplas camadas: hashes ancorados em consenso para o histórico de backfill, escritas condicionadas à finalização na ponta, e cross-validation ao vivo contínua por cima, garante que você pode confiar em um registro de verdade que avança no tempo.
O que você pode construir com isso
Toda pergunta do início deste post agora é uma chamada de API:
- "Qual era a conta do oracle exatamente naquele slot?" Uma chamada
getAccountInfocomslotdefinido. Extraia o estado exato de cada conta que uma transação com falha leu, no slot em que executou. Chega de reconstruir inputs de oracle a partir de screenshots e suposições. - "Reconstrua as reservas desse pool ao longo de seis meses." Amostre a conta do pool em uma cadência fixa de slots e faça o backtest contra o que de fato estava on chain, não uma aproximação montada a partir de eventos de trade.
- "Prove o que essa token account continha em 3 de março." "No slot S, a conta X continha exatamente estes bytes." Isso é respondível, e ancorado em hashes que a própria rede concordou.
- "Reconstrua as transições de estado que nosso indexer perdeu." Pagine para frente com
firstUpdateAfterSlota partir do último slot conhecido e receba cada estado intermediário, em ordem.
E uma que a introdução não perguntou: histórico de saldo e posição sem rodar um indexer nenhum. Percorra uma token account para trás com lastUpdateBeforeSlot e você tem sua linha do tempo completa. Para saldos de tokens em toda uma wallet em um slot passado, veja também historical Solana token balances.
Comece agora
A Solana se mantém rápida mantendo os validators enxutos e focados no estado atual. O estado histórico das contas simplesmente sempre viveu em outro lugar, e até agora o ecossistema tinha que contornar isso. O Solana Account Archive muda isso. Com ingestão ao vivo condicionada à finalização e um pipeline de backfill que reexecuta o histórico através de runtimes fiéis a cada época e prova o resultado contra hashes de consenso, o getAccountInfo histórico se torna apenas mais uma chamada RPC: mesmo método, mesmo formato de resposta, um parâmetro a mais.
Em um post seguinte, vamos nos aprofundar na camada de armazenamento: como um ano de escritas de contas da Solana é organizado em disco para que tanto a ingestão de novas atualizações quanto as respostas a queries em um ponto no tempo continuem rápidas. Tudo o que o archive indexa é comprimido, armazenado com pelo menos 3 réplicas para redundância, e nunca podado, de forma que a janela consultável só cresce.
Comece a usar a Solana, e entre em contato conosco se o seu caso de uso precisar de histórico mais profundo, ou se você quiser explorar soluções especializadas e preços em escala.
FAQ
Como eu obtenho o estado de uma conta Solana em um slot específico?
Chame getAccountInfo no Account Archive com a pubkey da conta e um parâmetro slot no objeto de config: getAccountInfo(pubkey, { "slot": S }). A resposta segue o formato padrão de getAccountInfo e retorna o estado da conta no slot S, a última escrita em ou antes de S.
Como eu obtenho o histórico completo de atualizações de uma conta Solana?
Pagine com os parâmetros de cursor. getAccountInfo(pubkey, { "lastUpdateBeforeSlot": S }) retorna a escrita mais recente estritamente antes de S, com o slot real da escrita em context.slot; devolva esse slot como o próximo cursor para percorrer, para trás, cada transição de estado. firstUpdateAfterSlot percorre para frente da mesma forma.
Qual é a diferença entre slot, lastUpdateBeforeSlot e firstUpdateAfterSlot?
slot é uma leitura em um ponto no tempo: estado no slot S, inclusive. lastUpdateBeforeSlot e firstUpdateAfterSlot são cursores de histórico exclusivos: a escrita mais próxima estritamente antes ou estritamente depois de S. Os três são mutuamente exclusivos; omita todos eles para uma leitura normal de estado mais recente.
O encoding jsonParsed funciona para estado histórico de contas?
Sim. Os mesmos decoders de conta que um node RPC Solana padrão usa são aplicados aos bytes históricos, então token accounts, mints e outras contas de programas conhecidos voltam parseadas em qualquer slot dentro da cobertura. Todos os encodings padrão funcionam: base64, base58, base64+zstd, e jsonParsed, mais dataSlice.
Até quando no passado eu posso consultar?
A cobertura atualmente se estende até julho de 2025, com o backfill estendendo-a ainda mais para trás ao longo do tempo. O histórico nunca é podado, então tudo que foi indexado permanece consultável e a janela só cresce.
Como se sabe que os dados históricos estão corretos?
Os intervalos de backfill são produzidos reexecutando cada transação através do runtime do validator da época correspondente, e o estado resultante é verificado contra os próprios artefatos de consenso da rede, incluindo o accounts lattice hash a partir de snapshots canônicos. A ingestão ao vivo só confirma slots finalizados, e um watchdog independente faz cross-checking contínuo dos resultados servidos contra nodes RPC ao vivo.
Todas as contas são cobertas?
Todas as contas, exceto a contabilidade interna pura por slot da chain: vote accounts e as três sysvars reescritas a cada slot (SlotHashes, SlotHistory, RecentBlockhashes) são excluídas do índice. Contas de programas, token accounts, mints, PDAs, wallets, e as demais sysvars (Clock, Rent, e assim por diante) estão todas cobertas.
Preciso de um novo SDK ou client?
Não. Qualquer client JSON-RPC da Solana funciona. O archive implementa getAccountInfo padrão, e os parâmetros históricos são apenas campos extras no objeto de config já existente.
Newsletter da Alchemy
Seja o primeiro a saber sobre lançamentos
Assine nossa newsletter
Receba as últimas atualizações de produtos e recursos da Alchemy
Ao inserir seu endereço de e-mail, você concorda em receber nossas comunicações de marketing e atualizações de produtos. Você reconhece que a Alchemy processa as informações que recebemos de acordo com nosso Aviso de Privacidade. Você pode cancelar a inscrição a qualquer momento.
Artigos relacionados

Glamsterdam: o guia completo para desenvolvedores de Ethereum
Glamsterdam já está na Sepolia. O guia completo sobre o que isso significa para desenvolvedores e como a Alchemy se preparou para a atualização da rede.

Em qual provedor de RPC você deve construir em Tóquio?
Comparamos cinco dos provedores de RPC que atendem Tóquio em cinco chains. Veja como eles se comparam e onde as diferenças importam para equipes sensíveis à latência.

Arquitetando leituras Solana RPC para velocidade e confiabilidade líderes do setor
A Alchemy tem a menor latência de leitura Solana: 9,21 ms, cerca de 26% mais rápido que o próximo provedor.