Skip to main content
Ao receber dados de transação do Laserstream, há duas coisas importantes a observar:
  • Message → O que o usuário queria fazer (sua proposta assinada)
  • Meta → O que realmente aconteceu (o resultado da execução)
O desafio: Dados brutos de transação vêm como arrays de bytes binários como <Buffer 00 bf a0 e8...> em vez de endereços e assinaturas legíveis. Este guia mostra como: Decodificar esses dados binários em formato legível, extrair informações significativas e entender toda a história da transação desde a proposta até a execução.

Uma transmissão ao vivo, sem decodificação

Execute o cliente mínimo abaixo. As flags de filtro descartam votos e transações falhas, e o array accountInclude limita os resultados a atividades que tocam o ID do programa Jupiter.
Seu console agora mostra um wrapper—filters, createdAt mais um branch transaction que oculta duas crianças:
  • transaction.transaction.transaction → a mensagem assinada
  • transaction.transaction.meta → o meta da execução
Tudo que parece Uint8Array permanece opaco por enquanto. Quando você executa o script com a função de decodificação, verá a estrutura aninhada real com endereços legíveis:

Decodificando os dados binários

Por que decodificar? Dados brutos do Laserstream contêm assinaturas, chaves de conta e hashes como objetos binários Uint8Array que são ilegíveis. Você precisa convertê-los para strings base58 para entender a transação. A solução: O Laserstream usa Yellowstone gRPC, que fornece utilitários de decodificação integrados. Em vez de escrever decodificadores separados para cada tipo de campo, usamos uma função recursiva que converte todos os dados binários em formato legível.
Esta abordagem aproveita a decodificação integrada enquanto lida com os campos binários que precisam de conversão manual. A estrutura da transação já está analisada - você só precisa converter os campos binários para um formato legível.

Entendendo a estrutura da transação

Agora que podemos ver os dados decodificados, vamos explorar as duas partes principais de cada atualização de transação do Laserstream. Lembre-se do nosso exemplo inicial de que cada transação contém dois objetos chave:
  • Message (Proposta)transaction.transaction.transaction → a mensagem assinada (proposta do usuário)
  • Meta (Execução)transaction.transaction.meta → os metadados da execução (resposta do validador)
Esta estrutura em duas partes conta uma história completa: o que o usuário solicitou versus o que realmente aconteceu. Vamos examinar cada parte em detalhe.

A proposta: tudo dentro da mensagem

O usuário cria uma mensagem que especifica o que, quem e até quando. Veja como decodificar cada parte:

Cabeçalho da Transação

numRequiredSignatures diz ao validador quantas assinaturas verificar, enquanto os dois valores numReadonly* rotulam contas que o runtime pode tratar como somente leitura, permitindo execução paralela.

Dicionário de Chaves de Conta

accountKeys é uma lista simples de chaves públicas que atua como uma tabela de consulta. Cada inteiro posterior na transação - programIdIndex, cada elemento em um array accounts de uma instrução - aponta de volta para esta lista por índice, salvando mais de um quilobyte por mensagem.

Proteção Contra Repetição

recentBlockhash expira uma vez que sai dos últimos 150 hashes de bloco, aproximadamente noventa segundos no mainnet.

Instruções: Os Comandos Reais

Cada instrução contém três partes principais:
  • ID do Programa (programIdIndex): Aponta para um endereço no array accountKeys (por exemplo, índice 10 = ComputeBudget111111111111111111111111111111)
  • Contas (accounts): Uma string codificada em base58 representando quais índices de conta essa instrução toca
  • Dados (data): Os dados reais da instrução codificados como base58
Devido à função convertBuffers, contas aparecem como base58, mas na verdade contêm índices de conta (por exemplo, "3vtmrQMafzDoG2CBz1iqgXPTnC" decodifica para índices [21, 19, 12, 17, 2, 6, 1, 22]) Este design significa que em vez de repetir endereços de 32 bytes completos, cada instrução apenas referencia posições na tabela de consulta.

Assinaturas: Prova de Autorização

signatures contém as assinaturas criptográficas provando que as contas necessárias autorizaram esta transação. O número de assinaturas deve coincidir com header.numRequiredSignatures.

Consultas de Tabela de Endereços

Se versioned é true, addressTableLookups aparece com uma tabela em cadeia e duas listas de índices. Tabelas de consulta elevam a limitação no número de endereços para dezenas, mantendo o pacote abaixo do MTU de 1.232 bytes.

Como Tudo se Conecta: O Fluxo

Aqui está o que acontece desde os primeiros princípios:
  1. Construa a tabela de consulta: accountKeys lista todos os endereços que esta transação tocará
  2. Estabeleça as regras: header especifica quantas assinaturas são necessárias e quais contas são somente leitura
  3. Crie os comandos: Cada instruction aponta para:
    • Um programa (via programIdIndexaccountKeys[index])
    • As contas que necessita (via accounts → múltiplas posições accountKeys[index])
    • Os dados da instrução (codificados em data)
  4. Adicione autorização: signatures comprova que as contas necessárias aprovaram esta transação
  5. Defina a expiração: recentBlockhash garante que esta transação não possa ser repetida posteriormente

A execução: tudo dentro do meta

Enquanto a mensagem mostra o que o usuário queria fazer, o meta mostra o que realmente aconteceu quando os validadores executaram a transação.

Informações básicas de execução

Sucesso/Falha
  • err: null = sucesso
  • err: {...} = falha com detalhes de erro
  • fee = lamports cobrados por esta transação
Mudanças de Saldo
Os arrays de saldo correspondem ao array accountKeys por índice:
  • Conta 0: Perdeu 15000 lamports (pagamento de taxa)
  • Conta 1: Ganhou 1461600 lamports (nova conta criada)
  • Conta 3: Ganhou 2001231920 lamports (conta do programa)
Uso de Computação
Mostra quanto do orçamento de computação foi usado (do total solicitado).

Detalhes avançados de execução

Instruções Internas
Instruções internas são instruções adicionais que programas chamaram durante a execução. Não fazem parte da transação original, mas foram acionadas pelas instruções principais. Mensagens de Log
Mensagens de log fornecem um rastreamento cronológico da execução do programa, mostrando quais programas foram chamados e qualquer mensagem de log personalizada que eles emitiram. Mudanças de Saldo de Token
As mudanças de saldo de token mostram os estados antes/depois para contas de token SPL, incluindo as quantidades legíveis com o tratamento decimal adequado.

Padrões práticos de decodificação

Aqui estão padrões comuns para extrair informações úteis de transações decodificadas:

Exemplo completo: decodificador de troca Jupiter

Aqui está um exemplo completo que decodifica transações de troca Jupiter e extrai informações significativas:
Este exemplo mostra como combinar decodificação de mensagem com análise de meta para extrair informações relevantes para negócios de transações DeFi complexas.

Pontos principais

  • Estrutura de duas partes: Cada transação tem uma mensagem (o que foi solicitado) e meta (o que realmente aconteceu)
  • Decodificação binária: Use bs58.encode() para converter campos binários em strings legíveis base58
  • Consultas de chave de conta: Instruções referenciam contas por índice no array accountKeys
  • Rastreamento de saldo: Compare preBalances e postBalances para ver o que mudou
A chave para entender transações Solana é reconhecer que elas são projetadas para eficiência: em vez de repetir endereços, usam tabelas de consulta e índices para minimizar o tamanho da transação enquanto maximizam a densidade da informação.