Skip to content

Commit

Permalink
Explorer: Refactor parsed transaction handling (#27050)
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry authored Aug 10, 2022
1 parent c03f3b1 commit 9348a23
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 90 deletions.
18 changes: 8 additions & 10 deletions explorer/src/components/account/TokenHistoryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,8 @@ const TokenTransactionRow = React.memo(
statusText = "Success";
}

const instructions =
details?.data?.transaction?.transaction.message.instructions;
const transactionWithMeta = details?.data?.transactionWithMeta;
const instructions = transactionWithMeta?.transaction.message.instructions;
if (!instructions)
return (
<tr key={tx.signature}>
Expand Down Expand Up @@ -424,9 +424,7 @@ const TokenTransactionRow = React.memo(

let tokenInstructionNames: InstructionType[] = [];

if (details?.data?.transaction) {
const transaction = details.data.transaction;

if (transactionWithMeta) {
tokenInstructionNames = instructions
.map((ix, index): InstructionType | undefined => {
let name = "Unknown";
Expand All @@ -437,11 +435,11 @@ const TokenTransactionRow = React.memo(
)[] = [];

if (
transaction.meta?.innerInstructions &&
transactionWithMeta.meta?.innerInstructions &&
(cluster !== Cluster.MainnetBeta ||
transaction.slot >= INNER_INSTRUCTIONS_START_SLOT)
transactionWithMeta.slot >= INNER_INSTRUCTIONS_START_SLOT)
) {
transaction.meta.innerInstructions.forEach((ix) => {
transactionWithMeta.meta.innerInstructions.forEach((ix) => {
if (ix.index === index) {
ix.instructions.forEach((inner) => {
innerInstructions.push(inner);
Expand All @@ -451,9 +449,9 @@ const TokenTransactionRow = React.memo(
}

let transactionInstruction;
if (transaction?.transaction) {
if (transactionWithMeta?.transaction) {
transactionInstruction = intoTransactionInstruction(
transaction.transaction,
transactionWithMeta.transaction,
ix
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import {
ParsedConfirmedTransaction,
ParsedTransactionWithMeta,
ParsedInstruction,
PartiallyDecodedInstruction,
PublicKey,
Expand Down Expand Up @@ -47,23 +47,23 @@ export function TokenInstructionsCard({ pubkey }: { pubkey: PublicKey }) {
const { hasTimestamps, detailsList } = React.useMemo(() => {
const detailedHistoryMap =
history?.data?.transactionMap ||
new Map<string, ParsedConfirmedTransaction>();
new Map<string, ParsedTransactionWithMeta>();
const hasTimestamps = transactionRows.some((element) => element.blockTime);
const detailsList: React.ReactNode[] = [];
const mintMap = new Map<string, MintDetails>();

transactionRows.forEach(
({ signatureInfo, signature, blockTime, statusClass, statusText }) => {
const parsed = detailedHistoryMap.get(signature);
if (!parsed) return;
const transactionWithMeta = detailedHistoryMap.get(signature);
if (!transactionWithMeta) return;

extractMintDetails(parsed, mintMap);
extractMintDetails(transactionWithMeta, mintMap);

let instructions: (ParsedInstruction | PartiallyDecodedInstruction)[] =
[];

InstructionContainer.create(parsed).instructions.forEach(
({ instruction, inner }, index) => {
InstructionContainer.create(transactionWithMeta).instructions.forEach(
({ instruction, inner }) => {
if (isRelevantInstruction(pubkey, address, mintMap, instruction)) {
instructions.push(instruction);
}
Expand All @@ -79,7 +79,7 @@ export function TokenInstructionsCard({ pubkey }: { pubkey: PublicKey }) {
const programId = ix.programId;

const instructionName = getTokenInstructionName(
parsed,
transactionWithMeta,
ix,
signatureInfo
);
Expand Down
12 changes: 6 additions & 6 deletions explorer/src/components/account/history/TokenTransfersCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import {
ParsedConfirmedTransaction,
ParsedTransactionWithMeta,
ParsedInstruction,
PartiallyDecodedInstruction,
PublicKey,
Expand Down Expand Up @@ -68,23 +68,23 @@ export function TokenTransfersCard({ pubkey }: { pubkey: PublicKey }) {
const { hasTimestamps, detailsList } = React.useMemo(() => {
const detailedHistoryMap =
history?.data?.transactionMap ||
new Map<string, ParsedConfirmedTransaction>();
new Map<string, ParsedTransactionWithMeta>();
const hasTimestamps = transactionRows.some((element) => element.blockTime);
const detailsList: React.ReactNode[] = [];
const mintMap = new Map<string, MintDetails>();

transactionRows.forEach(
({ signature, blockTime, statusText, statusClass }) => {
const parsed = detailedHistoryMap.get(signature);
if (!parsed) return;
const transactionWithMeta = detailedHistoryMap.get(signature);
if (!transactionWithMeta) return;

// Extract mint information from token deltas
// (used to filter out non-checked tokens transfers not belonging to this mint)
extractMintDetails(parsed, mintMap);
extractMintDetails(transactionWithMeta, mintMap);

// Extract all transfers from transaction
let transfers: IndexedTransfer[] = [];
InstructionContainer.create(parsed).instructions.forEach(
InstructionContainer.create(transactionWithMeta).instructions.forEach(
({ instruction, inner }, index) => {
const transfer = getTransfer(instruction, cluster, signature);
if (transfer) {
Expand Down
20 changes: 12 additions & 8 deletions explorer/src/components/account/history/common.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
import { ParsedConfirmedTransaction } from "@solana/web3.js";
import { ParsedTransactionWithMeta } from "@solana/web3.js";

export type MintDetails = {
decimals: number;
mint: string;
};

export function extractMintDetails(
parsedTransaction: ParsedConfirmedTransaction,
transactionWithMeta: ParsedTransactionWithMeta,
mintMap: Map<string, MintDetails>
) {
if (parsedTransaction.meta?.preTokenBalances) {
parsedTransaction.meta.preTokenBalances.forEach((balance) => {
if (transactionWithMeta.meta?.preTokenBalances) {
transactionWithMeta.meta.preTokenBalances.forEach((balance) => {
const account =
parsedTransaction.transaction.message.accountKeys[balance.accountIndex];
transactionWithMeta.transaction.message.accountKeys[
balance.accountIndex
];
mintMap.set(account.pubkey.toBase58(), {
decimals: balance.uiTokenAmount.decimals,
mint: balance.mint,
});
});
}

if (parsedTransaction.meta?.postTokenBalances) {
parsedTransaction.meta.postTokenBalances.forEach((balance) => {
if (transactionWithMeta.meta?.postTokenBalances) {
transactionWithMeta.meta.postTokenBalances.forEach((balance) => {
const account =
parsedTransaction.transaction.message.accountKeys[balance.accountIndex];
transactionWithMeta.transaction.message.accountKeys[
balance.accountIndex
];
mintMap.set(account.pubkey.toBase58(), {
decimals: balance.uiTokenAmount.decimals,
mint: balance.mint,
Expand Down
8 changes: 4 additions & 4 deletions explorer/src/components/transaction/InstructionsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ export function InstructionsSection({ signature }: SignatureProps) {
const refreshDetails = () => fetchDetails(signature);

const result = status?.data?.info?.result;
if (!result || !details?.data?.transaction) {
const transactionWithMeta = details?.data?.transactionWithMeta;
if (!result || !transactionWithMeta) {
return <ErrorCard retry={refreshDetails} text="No instructions found" />;
}
const { meta } = details.data.transaction;
const { transaction } = details.data?.transaction;
const { meta, transaction } = transactionWithMeta;

if (transaction.message.instructions.length === 0) {
return <ErrorCard retry={refreshDetails} text="No instructions found" />;
Expand All @@ -83,7 +83,7 @@ export function InstructionsSection({ signature }: SignatureProps) {
if (
meta?.innerInstructions &&
(cluster !== Cluster.MainnetBeta ||
details.data.transaction.slot >= INNER_INSTRUCTIONS_START_SLOT)
transactionWithMeta.slot >= INNER_INSTRUCTIONS_START_SLOT)
) {
meta.innerInstructions.forEach((parsed: ParsedInnerInstruction) => {
if (!innerInstructions[parsed.index]) {
Expand Down
10 changes: 5 additions & 5 deletions explorer/src/components/transaction/ProgramLogSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export function ProgramLogSection({ signature }: SignatureProps) {
const { cluster, url } = useCluster();
const details = useTransactionDetails(signature);

const transaction = details?.data?.transaction;
if (!transaction) return null;
const message = transaction.transaction.message;
const transactionWithMeta = details?.data?.transactionWithMeta;
if (!transactionWithMeta) return null;
const message = transactionWithMeta.transaction.message;

const logMessages = transaction.meta?.logMessages || null;
const err = transaction.meta?.err || null;
const logMessages = transactionWithMeta.meta?.logMessages || null;
const err = transactionWithMeta.meta?.err || null;

let prettyLogs = null;
if (logMessages !== null) {
Expand Down
9 changes: 4 additions & 5 deletions explorer/src/components/transaction/TokenBalancesCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ export function TokenBalancesCard({ signature }: SignatureProps) {
return null;
}

const preTokenBalances = details.data?.transaction?.meta?.preTokenBalances;
const postTokenBalances = details.data?.transaction?.meta?.postTokenBalances;

const accountKeys =
details.data?.transaction?.transaction.message.accountKeys;
const transactionWithMeta = details.data?.transactionWithMeta;
const preTokenBalances = transactionWithMeta?.meta?.preTokenBalances;
const postTokenBalances = transactionWithMeta?.meta?.postTokenBalances;
const accountKeys = transactionWithMeta?.transaction.message.accountKeys;

if (!preTokenBalances || !postTokenBalances || !accountKeys) {
return null;
Expand Down
15 changes: 9 additions & 6 deletions explorer/src/pages/TransactionDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ function StatusCard({
}
}

const fee = details?.data?.transaction?.meta?.fee;
const transaction = details?.data?.transaction?.transaction;
const transactionWithMeta = details?.data?.transactionWithMeta;
const fee = transactionWithMeta?.meta?.fee;
const transaction = transactionWithMeta?.transaction;
const blockhash = transaction?.message.recentBlockhash;
const isNonce = (() => {
if (!transaction || transaction.message.instructions.length < 1) {
Expand Down Expand Up @@ -338,7 +339,8 @@ function DetailsSection({ signature }: SignatureProps) {
const details = useTransactionDetails(signature);
const fetchDetails = useFetchTransactionDetails();
const status = useTransactionStatus(signature);
const transaction = details?.data?.transaction?.transaction;
const transactionWithMeta = details?.data?.transactionWithMeta;
const transaction = transactionWithMeta?.transaction;
const message = transaction?.message;
const { status: clusterStatus } = useCluster();
const refreshDetails = () => fetchDetails(signature);
Expand All @@ -360,7 +362,7 @@ function DetailsSection({ signature }: SignatureProps) {
return <LoadingCard />;
} else if (details.status === FetchStatus.FetchFailed) {
return <ErrorCard retry={refreshDetails} text="Failed to fetch details" />;
} else if (!details.data?.transaction || !message) {
} else if (!transactionWithMeta || !message) {
return <ErrorCard text="Details are not available" />;
}

Expand All @@ -377,11 +379,12 @@ function DetailsSection({ signature }: SignatureProps) {
function AccountsCard({ signature }: SignatureProps) {
const details = useTransactionDetails(signature);

if (!details?.data?.transaction) {
const transactionWithMeta = details?.data?.transactionWithMeta;
if (!transactionWithMeta) {
return null;
}

const { meta, transaction } = details.data.transaction;
const { meta, transaction } = transactionWithMeta;
const { message } = transaction;

if (!meta) {
Expand Down
15 changes: 9 additions & 6 deletions explorer/src/providers/accounts/history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
ConfirmedSignatureInfo,
TransactionSignature,
Connection,
ParsedConfirmedTransaction,
ParsedTransactionWithMeta,
} from "@solana/web3.js";
import { useCluster, Cluster } from "../cluster";
import * as Cache from "providers/cache";
Expand All @@ -13,7 +13,7 @@ import { reportError } from "utils/sentry";

const MAX_TRANSACTION_BATCH_SIZE = 10;

type TransactionMap = Map<string, ParsedConfirmedTransaction>;
type TransactionMap = Map<string, ParsedTransactionWithMeta>;

type AccountHistory = {
fetched: ConfirmedSignatureInfo[];
Expand Down Expand Up @@ -109,11 +109,14 @@ async function fetchParsedTransactions(
0,
MAX_TRANSACTION_BATCH_SIZE
);
const fetched = await connection.getParsedConfirmedTransactions(signatures);
const fetched = await connection.getParsedTransactions(signatures);
fetched.forEach(
(parsed: ParsedConfirmedTransaction | null, index: number) => {
if (parsed !== null) {
transactionMap.set(signatures[index], parsed);
(
transactionWithMeta: ParsedTransactionWithMeta | null,
index: number
) => {
if (transactionWithMeta !== null) {
transactionMap.set(signatures[index], transactionWithMeta);
}
}
);
Expand Down
10 changes: 5 additions & 5 deletions explorer/src/providers/transactions/parsed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import React from "react";
import {
Connection,
TransactionSignature,
ParsedConfirmedTransaction,
ParsedTransactionWithMeta,
} from "@solana/web3.js";
import { useCluster, Cluster } from "../cluster";
import * as Cache from "providers/cache";
import { ActionType, FetchStatus } from "providers/cache";
import { reportError } from "utils/sentry";

export interface Details {
transaction?: ParsedConfirmedTransaction | null;
transactionWithMeta?: ParsedTransactionWithMeta | null;
}

type State = Cache.State<Details>;
Expand Down Expand Up @@ -53,9 +53,9 @@ async function fetchDetails(
});

let fetchStatus;
let transaction;
let transactionWithMeta;
try {
transaction = await new Connection(url).getParsedConfirmedTransaction(
transactionWithMeta = await new Connection(url).getParsedTransaction(
signature,
"confirmed"
);
Expand All @@ -70,7 +70,7 @@ async function fetchDetails(
type: ActionType.Update,
status: fetchStatus,
key: signature,
data: { transaction },
data: { transactionWithMeta },
url,
});
}
Expand Down
Loading

1 comment on commit 9348a23

@denispalab
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for explorer ready!

✅ Preview
https://explorer-q0iv6lda4-solana-labs.vercel.app

Built with commit 9348a23.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.