Riepilogo
@solana/transaction-introspection trasforma una risposta RPC
getTransaction in un elenco di istruzioni con indirizzi reali. Risolve gli
indici degli account (inclusi gli indirizzi delle lookup table), decodifica le
istruzioni CPI interne e scorre l'intero albero delle istruzioni nell'ordine
dell'explorer.
Stai cercando come un programma ispeziona le istruzioni adiacenti on-chain in fase di esecuzione? Questo è il sysvar Instructions - consulta Introspezione delle Istruzioni. Questa pagina riguarda la decodifica di una transazione off-chain da una risposta RPC.
Una risposta getTransaction non fornisce
direttamente un elenco di istruzioni pronto all'uso. Gli account sono
memorizzati come indici numerici, le
transazioni con versione
suddividono quegli account in chiavi statiche e indirizzi caricati dalle
Address Lookup Table, e le
istruzioni interne provenienti da Cross Program Invocation (CPI) arrivano come
blob codificati nei metadati della transazione.
@solana/transaction-introspection esegue questa risoluzione automaticamente.
Decodifica la transazione in formato wire, mappa ogni indice di account al suo
Address corrispondente, normalizza le istruzioni interne e restituisce le
istruzioni nello stesso ordine esterno-poi-interno visualizzato da un block
explorer. Le istruzioni restituite si integrano direttamente con gli helper
parseXInstruction dei client generati da codama (ad es., @solana-program/*
).
npm install @solana/transaction-introspection @solana/kit @solana/instructions @solana-program/token
Decodifica la risposta
Recupera la transazione con una codifica in formato wire e passa la risposta a
decodeTransactionFromRpcResponse.
import { createSolanaRpc, signature } from "@solana/kit";import { decodeTransactionFromRpcResponse } from "@solana/transaction-introspection";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const txid ="3jUKrQp1UGq5ih6FTDUUt2kkqUfoG2o4kY5T1DoVHK2tXXDLdxJSXzuJGY4JPoRivgbi45U2bc7LZfMa6C4R3szX";const rpcTx = await rpc.getTransaction(signature(txid), {commitment: "confirmed",encoding: "base64",maxSupportedTransactionVersion: 0}).send();if (!rpcTx) throw new Error(`Transaction ${txid} not found`);const { compiledMessage, loadedAddresses } =decodeTransactionFromRpcResponse(rpcTx);
I frammenti di codice successivi riutilizzano rpcTx, compiledMessage e
loadedAddresses da questo passaggio.
Effettua il fetch con la codifica base64, base58 o json.
decodeTransactionFromRpcResponse rifiuta le risposte jsonParsed - quella
codifica chiede al nodo RPC di analizzare le istruzioni lato server, quindi
non rimane nulla da decodificare sul client.
Scorri le istruzioni
walkInstructions restituisce ogni istruzione - esterna e interna - come array
nell'ordine mostrato da un block explorer: ogni istruzione esterna seguita
immediatamente dalle istruzioni interne prodotte dai suoi CPI. Ogni istruzione
contiene un campo trace che descrive la sua posizione nella gerarchia delle
chiamate.
import { walkInstructions } from "@solana/transaction-introspection";for (const ix of walkInstructions({compiledMessage,loadedAddresses,meta: rpcTx.meta})) {const location =ix.trace.kind === "outer"? `outer[${ix.trace.index}]`: `inner[${ix.trace.outerIndex}/${ix.trace.innerIndex}]`;console.log(location, ix.programAddress, ix.accounts?.length ?? 0);}
Il campo trace è un'unione discriminata: { kind: "outer", index } per
un'istruzione di primo livello, oppure
{ kind: "inner", outerIndex, innerIndex, stackHeight? } per un'istruzione CPI
annidata sotto una esterna.
meta è opzionale - passa rpcTx.meta direttamente anche quando potrebbe
essere null. Senza meta, walkInstructions restituisce solo le istruzioni
esterne.
Analizza con un client di programma
Ogni istruzione restituita da walkInstructions è un ResolvedInstruction,
quindi funziona direttamente con i predicati di @solana/instructions e con gli
helper identifyXInstruction / parseXInstruction generati dai client
@solana-program/* - senza alcun passaggio di conversione.
Questo esempio verifica ogni istruzione SyncNative del Token Program in una
transazione, sia che sia stata eseguita al livello superiore sia all'interno di
un CPI.
import {isInstructionForProgram,isInstructionWithAccounts,isInstructionWithData} from "@solana/instructions";import { walkInstructions } from "@solana/transaction-introspection";import {identifyTokenInstruction,parseSyncNativeInstruction,TOKEN_PROGRAM_ADDRESS,TokenInstruction} from "@solana-program/token";for (const ix of walkInstructions({compiledMessage,loadedAddresses,meta: rpcTx.meta})) {if (!isInstructionForProgram(ix, TOKEN_PROGRAM_ADDRESS)) continue;if (!isInstructionWithData(ix) || !isInstructionWithAccounts(ix)) continue;if (identifyTokenInstruction(ix) !== TokenInstruction.SyncNative) continue;const parsed = parseSyncNativeInstruction(ix);console.log(ix.trace, parsed);}
Helper di livello inferiore
walkInstructions copre la maggior parte delle esigenze, ma il pacchetto espone
anche i componenti su cui si basa:
getInstructionsFromCompiledTransactionMessage(compiledMessage, loadedAddresses?)restituisce solo le istruzioni esterne, con account risolti e dati decodificati.getInnerInstructionsFromMeta(meta, accountMetas)decodifica le istruzioni CPI interne dai metadati della transazione.getAccountMetasFromCompiledTransactionMessage(compiledMessage, loadedAddresses?)restituisce l'elenco completo degli account nell'ordine della transazione - l'input necessario all'helper precedente per risolvere gli indici degli account delle istruzioni interne.
import {getAccountMetasFromCompiledTransactionMessage,getInnerInstructionsFromMeta,getInstructionsFromCompiledTransactionMessage} from "@solana/transaction-introspection";const outer = getInstructionsFromCompiledTransactionMessage(compiledMessage,loadedAddresses);const accountMetas = getAccountMetasFromCompiledTransactionMessage(compiledMessage,loadedAddresses);if (!rpcTx.meta) throw new Error("Transaction metadata missing");const inner = getInnerInstructionsFromMeta(rpcTx.meta, accountMetas);
Stai usando Rust?
Non esiste un equivalente Rust di questo pacchetto. Per ottenere istruzioni
analizzate da Rust, richiedi UiTransactionEncoding::JsonParsed da
getTransaction e lascia che il nodo RPC
risolva gli account e le istruzioni interne per te.
Vedi anche
- Struttura della transazione - l'anatomia della risposta decodificata da questo pacchetto
- Transazioni con versione - come le tabelle di ricerca degli indirizzi suddividono gli account in gruppi statici e caricati
getTransaction- il metodo RPC che restituisce la transazione
Is this page helpful?