Skip to content

Commit

Permalink
Explorer: Support displaying and inspecting versioned transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Sep 24, 2022
1 parent e85900e commit 7766902
Show file tree
Hide file tree
Showing 20 changed files with 376 additions and 129 deletions.
27 changes: 12 additions & 15 deletions explorer/src/components/ProgramLogsCardBody.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Message, ParsedMessage } from "@solana/web3.js";
import { ParsedMessage, PublicKey, VersionedMessage } from "@solana/web3.js";
import { Cluster } from "providers/cluster";
import { TableCardBody } from "components/common/TableCardBody";
import { InstructionLogs } from "utils/program-logs";
Expand All @@ -21,27 +21,24 @@ export function ProgramLogsCardBody({
cluster,
url,
}: {
message: Message | ParsedMessage;
message: VersionedMessage | ParsedMessage;
logs: InstructionLogs[];
cluster: Cluster;
url: string;
}) {
let logIndex = 0;
let instructionProgramIds: PublicKey[];
if ("compiledInstructions" in message) {
instructionProgramIds = message.compiledInstructions.map((ix) => {
return message.staticAccountKeys[ix.programIdIndex];
});
} else {
instructionProgramIds = message.instructions.map((ix) => ix.programId);
}

return (
<TableCardBody>
{message.instructions.map((ix, index) => {
let programId;
if ("programIdIndex" in ix) {
const programAccount = message.accountKeys[ix.programIdIndex];
if ("pubkey" in programAccount) {
programId = programAccount.pubkey;
} else {
programId = programAccount;
}
} else {
programId = ix.programId;
}

{instructionProgramIds.map((programId, index) => {
const programAddress = programId.toBase58();
let programLogs: InstructionLogs | undefined = logs[logIndex];
if (programLogs?.invokedProgram === programAddress) {
Expand Down
18 changes: 13 additions & 5 deletions explorer/src/components/block/BlockAccountsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { BlockResponse, PublicKey } from "@solana/web3.js";
import { PublicKey, VersionedBlockResponse } from "@solana/web3.js";
import { Address } from "components/common/Address";
import { Link } from "react-router-dom";
import { clusterPath } from "utils/url";
Expand All @@ -15,7 +15,7 @@ export function BlockAccountsCard({
block,
blockSlot,
}: {
block: BlockResponse;
block: VersionedBlockResponse;
blockSlot: number;
}) {
const [numDisplayed, setNumDisplayed] = React.useState(10);
Expand All @@ -25,10 +25,18 @@ export function BlockAccountsCard({
const statsMap = new Map<string, AccountStats>();
block.transactions.forEach((tx) => {
const message = tx.transaction.message;
const getAccountKeysArgs = tx.meta?.loadedAddresses
? {
accountKeysFromLookups: tx.meta.loadedAddresses,
}
: undefined;
const txSet = new Map<string, boolean>();
message.instructions.forEach((ix) => {
ix.accounts.forEach((index) => {
const address = message.accountKeys[index].toBase58();
message.compiledInstructions.forEach((ix) => {
ix.accountKeyIndexes.forEach((index) => {
const address = message
.getAccountKeys(getAccountKeysArgs)
.get(index)!
.toBase58();
txSet.set(address, message.isAccountWritable(index));
});
});
Expand Down
28 changes: 22 additions & 6 deletions explorer/src/components/block/BlockHistoryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from "react";
import { Link, useHistory, useLocation } from "react-router-dom";
import { Location } from "history";
import {
BlockResponse,
ConfirmedTransactionMeta,
TransactionSignature,
PublicKey,
VOTE_PROGRAM_ID,
VersionedBlockResponse,
} from "@solana/web3.js";
import { ErrorCard } from "components/common/ErrorCard";
import { Signature } from "components/common/Signature";
Expand Down Expand Up @@ -51,7 +51,7 @@ type TransactionWithInvocations = {
logTruncated: boolean;
};

export function BlockHistoryCard({ block }: { block: BlockResponse }) {
export function BlockHistoryCard({ block }: { block: VersionedBlockResponse }) {
const [numDisplayed, setNumDisplayed] = React.useState(PAGE_SIZE);
const [showDropdown, setDropdown] = React.useState(false);
const query = useQuery();
Expand All @@ -72,7 +72,7 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {
signature = tx.transaction.signatures[0];
}

let programIndexes = tx.transaction.message.instructions
let programIndexes = tx.transaction.message.compiledInstructions
.map((ix) => ix.programIdIndex)
.concat(
tx.meta?.innerInstructions?.flatMap((ix) => {
Expand All @@ -87,8 +87,14 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {
});

const invocations = new Map<string, number>();
const accountKeysFromLookups = tx.meta?.loadedAddresses;
const accountKeys = tx.transaction.message.getAccountKeys(
accountKeysFromLookups && {
accountKeysFromLookups,
}
);
for (const [i, count] of indexMap.entries()) {
const programId = tx.transaction.message.accountKeys[i].toBase58();
const programId = accountKeys.get(i)!.toBase58();
invocations.set(programId, count);
const programTransactionCount = invokedPrograms.get(programId) || 0;
invokedPrograms.set(programId, programTransactionCount + 1);
Expand Down Expand Up @@ -143,8 +149,18 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {
if (accountFilter === null) {
return true;
}
const tx = block.transactions[index].transaction;
return tx.message.accountKeys.find((key) => key.equals(accountFilter));

const tx = block.transactions[index];
const accountKeysFromLookups = tx.meta?.loadedAddresses;
const accountKeys = tx.transaction.message.getAccountKeys(
accountKeysFromLookups && {
accountKeysFromLookups,
}
);
return accountKeys
.keySegments()
.flat()
.find((key) => key.equals(accountFilter));
});

const showComputeUnits = filteredTxs.every(
Expand Down
4 changes: 2 additions & 2 deletions explorer/src/components/block/BlockOverviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Slot } from "components/common/Slot";
import { ClusterStatus, useCluster } from "providers/cluster";
import { BlockHistoryCard } from "./BlockHistoryCard";
import { BlockRewardsCard } from "./BlockRewardsCard";
import { BlockResponse } from "@solana/web3.js";
import { VersionedBlockResponse } from "@solana/web3.js";
import { NavLink } from "react-router-dom";
import { clusterPath } from "utils/url";
import { BlockProgramsCard } from "./BlockProgramsCard";
Expand Down Expand Up @@ -211,7 +211,7 @@ function MoreSection({
tab,
}: {
slot: number;
block: BlockResponse;
block: VersionedBlockResponse;
tab?: string;
}) {
return (
Expand Down
24 changes: 18 additions & 6 deletions explorer/src/components/block/BlockProgramsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from "react";
import { BlockResponse, PublicKey } from "@solana/web3.js";
import { PublicKey, VersionedBlockResponse } from "@solana/web3.js";
import { Address } from "components/common/Address";
import { TableCardBody } from "components/common/TableCardBody";

export function BlockProgramsCard({ block }: { block: BlockResponse }) {
export function BlockProgramsCard({
block,
}: {
block: VersionedBlockResponse;
}) {
const totalTransactions = block.transactions.length;
const txSuccesses = new Map<string, number>();
const txFrequency = new Map<string, number>();
Expand All @@ -12,18 +16,26 @@ export function BlockProgramsCard({ block }: { block: BlockResponse }) {
let totalInstructions = 0;
block.transactions.forEach((tx) => {
const message = tx.transaction.message;
totalInstructions += message.instructions.length;
totalInstructions += message.compiledInstructions.length;
const programUsed = new Set<string>();
const accountKeysFromLookups = tx.meta?.loadedAddresses;
const accountKeys = tx.transaction.message.getAccountKeys(
accountKeysFromLookups && {
accountKeysFromLookups,
}
);
const trackProgram = (index: number) => {
if (index >= message.accountKeys.length) return;
const programId = message.accountKeys[index];
if (index >= accountKeys.length) return;
const programId = accountKeys.get(index)!;
const programAddress = programId.toBase58();
programUsed.add(programAddress);
const frequency = ixFrequency.get(programAddress);
ixFrequency.set(programAddress, frequency ? frequency + 1 : 1);
};

message.instructions.forEach((ix) => trackProgram(ix.programIdIndex));
message.compiledInstructions.forEach((ix) =>
trackProgram(ix.programIdIndex)
);
tx.meta?.innerInstructions?.forEach((inner) => {
totalInstructions += inner.instructions.length;
inner.instructions.forEach((innerIx) =>
Expand Down
4 changes: 2 additions & 2 deletions explorer/src/components/block/BlockRewardsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from "react";
import { SolBalance } from "utils";
import { BlockResponse, PublicKey } from "@solana/web3.js";
import { PublicKey, VersionedBlockResponse } from "@solana/web3.js";
import { Address } from "components/common/Address";

const PAGE_SIZE = 10;

export function BlockRewardsCard({ block }: { block: BlockResponse }) {
export function BlockRewardsCard({ block }: { block: VersionedBlockResponse }) {
const [rewardsDisplayed, setRewardsDisplayed] = React.useState(PAGE_SIZE);

if (!block.rewards || block.rewards.length < 1) {
Expand Down
13 changes: 13 additions & 0 deletions explorer/src/pages/TransactionDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ function StatusCard({
const fee = transactionWithMeta?.meta?.fee;
const transaction = transactionWithMeta?.transaction;
const blockhash = transaction?.message.recentBlockhash;
const version = transactionWithMeta?.version;
const isNonce = (() => {
if (!transaction || transaction.message.instructions.length < 1) {
return false;
Expand Down Expand Up @@ -330,6 +331,13 @@ function StatusCard({
</td>
</tr>
)}

{version !== undefined && (
<tr>
<td>Transaction Version</td>
<td className="text-lg-end text-uppercase">{version}</td>
</tr>
)}
</TableCardBody>
</div>
);
Expand Down Expand Up @@ -420,6 +428,11 @@ function AccountsCard({ signature }: SignatureProps) {
{account.signer && (
<span className="badge bg-info-soft me-1">Signer</span>
)}
{account.source === "lookupTable" && (
<span className="badge bg-info-soft me-1">
Address Table Lookup
</span>
)}
{message.instructions.find((ix) => ix.programId.equals(pubkey)) && (
<span className="badge bg-info-soft me-1">Program</span>
)}
Expand Down
Loading

0 comments on commit 7766902

Please sign in to comment.