- Message → O que o usuário queria fazer (sua proposta assinada)
- Meta → O que realmente aconteceu (o resultado da execução)
<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 arrayaccountInclude limita os resultados a atividades que tocam o ID do programa Jupiter.
filters, createdAt mais um branch transaction que oculta duas crianças:
transaction.transaction.transaction→ a mensagem assinadatransaction.transaction.meta→ o meta da execução
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áriosUint8Array 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.
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)
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
- ID do Programa (
programIdIndex): Aponta para um endereço no arrayaccountKeys(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
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
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:- Construa a tabela de consulta:
accountKeyslista todos os endereços que esta transação tocará - Estabeleça as regras:
headerespecifica quantas assinaturas são necessárias e quais contas são somente leitura - Crie os comandos: Cada
instructionaponta para:- Um programa (via
programIdIndex→accountKeys[index]) - As contas que necessita (via
accounts→ múltiplas posiçõesaccountKeys[index]) - Os dados da instrução (codificados em
data)
- Um programa (via
- Adicione autorização:
signaturescomprova que as contas necessárias aprovaram esta transação - Defina a expiração:
recentBlockhashgarante 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/Falhaerr: null= sucessoerr: {...}= falha com detalhes de errofee= lamports cobrados por esta transação
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)
Detalhes avançados de execução
Instruções InternasPadrõ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: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
preBalancesepostBalancespara ver o que mudou