Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
explorer: Support filtering block transactions by account (#24787)
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry authored Apr 28, 2022
1 parent 8f26806 commit 898b352
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 18 deletions.
21 changes: 19 additions & 2 deletions explorer/src/components/block/BlockAccountsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import { BlockResponse, PublicKey } from "@solana/web3.js";
import { Address } from "components/common/Address";
import { Link } from "react-router-dom";
import { clusterPath } from "utils/url";

type AccountStats = {
reads: number;
Expand All @@ -9,7 +11,13 @@ type AccountStats = {

const PAGE_SIZE = 25;

export function BlockAccountsCard({ block }: { block: BlockResponse }) {
export function BlockAccountsCard({
block,
blockSlot,
}: {
block: BlockResponse;
blockSlot: number;
}) {
const [numDisplayed, setNumDisplayed] = React.useState(10);
const totalTransactions = block.transactions.length;

Expand Down Expand Up @@ -76,7 +84,16 @@ export function BlockAccountsCard({ block }: { block: BlockResponse }) {
return (
<tr key={address}>
<td>
<Address pubkey={new PublicKey(address)} link />
<Link
to={clusterPath(
`/block/${blockSlot}`,
new URLSearchParams(
`accountFilter=${address}&filter=all`
)
)}
>
<Address pubkey={new PublicKey(address)} />
</Link>
</td>
<td>{writes}</td>
<td>{reads}</td>
Expand Down
64 changes: 49 additions & 15 deletions explorer/src/components/block/BlockHistoryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@ import { parseProgramLogs } from "utils/program-logs";

const PAGE_SIZE = 25;

const useQueryFilter = (query: URLSearchParams): string => {
const useQueryProgramFilter = (query: URLSearchParams): string => {
const filter = query.get("filter");
return filter || "";
};

const useQueryAccountFilter = (query: URLSearchParams): PublicKey | null => {
const filter = query.get("accountFilter");
if (filter !== null) {
try {
return new PublicKey(filter);
} catch {}
}
return null;
};

type SortMode = "index" | "compute";
const useQuerySort = (query: URLSearchParams): SortMode => {
const sort = query.get("sort");
Expand All @@ -43,7 +53,8 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {
const [numDisplayed, setNumDisplayed] = React.useState(PAGE_SIZE);
const [showDropdown, setDropdown] = React.useState(false);
const query = useQuery();
const filter = useQueryFilter(query);
const programFilter = useQueryProgramFilter(query);
const accountFilter = useQueryAccountFilter(query);
const sortMode = useQuerySort(query);
const { cluster } = useCluster();
const location = useLocation();
Expand Down Expand Up @@ -107,26 +118,40 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {

const filteredTransactions = React.useMemo(() => {
const voteFilter = VOTE_PROGRAM_ID.toBase58();
const filteredTxs = transactions.filter(({ invocations }) => {
if (filter === ALL_TRANSACTIONS) {
return true;
} else if (filter === HIDE_VOTES) {
// hide vote txs that don't invoke any other programs
return !(invocations.size === 1 || invocations.has(voteFilter));
}
return invocations.has(filter);
});
const filteredTxs = transactions
.filter(({ invocations }) => {
if (programFilter === ALL_TRANSACTIONS) {
return true;
} else if (programFilter === HIDE_VOTES) {
// hide vote txs that don't invoke any other programs
return !(invocations.size === 1 || invocations.has(voteFilter));
}
return invocations.has(programFilter);
})
.filter(({ index }) => {
if (accountFilter === null) {
return true;
}
const tx = block.transactions[index].transaction;
return tx.message.accountKeys.find((key) => key.equals(accountFilter));
});

if (sortMode === "compute") {
filteredTxs.sort((a, b) => b.computeUnits - a.computeUnits);
}

return filteredTxs;
}, [transactions, filter, sortMode]);
}, [
block.transactions,
transactions,
programFilter,
accountFilter,
sortMode,
]);

if (filteredTransactions.length === 0) {
const errorMessage =
filter === ALL_TRANSACTIONS
programFilter === ALL_TRANSACTIONS
? "This block has no transactions"
: "No transactions found with this filter";
return <ErrorCard text={errorMessage} />;
Expand All @@ -144,14 +169,23 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {
<div className="card-header align-items-center">
<h3 className="card-header-title">{title}</h3>
<FilterDropdown
filter={filter}
filter={programFilter}
toggle={() => setDropdown((show) => !show)}
show={showDropdown}
invokedPrograms={invokedPrograms}
totalTransactionCount={transactions.length}
></FilterDropdown>
</div>

{accountFilter !== null && (
<div className="card-body">
Showing transactions which load account:
<div className="d-inline-block ms-2">
<Address pubkey={accountFilter} link />
</div>
</div>
)}

<div className="table-responsive mb-0">
<table className="table table-sm table-nowrap card-table">
<thead>
Expand Down Expand Up @@ -234,7 +268,7 @@ export function BlockHistoryCard({ block }: { block: BlockResponse }) {
</table>
</div>

{block.transactions.length > numDisplayed && (
{filteredTransactions.length > numDisplayed && (
<div className="card-footer">
<button
className="btn btn-primary w-100"
Expand Down
4 changes: 3 additions & 1 deletion explorer/src/components/block/BlockOverviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ function MoreSection({
</div>
{tab === undefined && <BlockHistoryCard block={block} />}
{tab === "rewards" && <BlockRewardsCard block={block} />}
{tab === "accounts" && <BlockAccountsCard block={block} />}
{tab === "accounts" && (
<BlockAccountsCard block={block} blockSlot={slot} />
)}
{tab === "programs" && <BlockProgramsCard block={block} />}
</>
);
Expand Down

1 comment on commit 898b352

@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-ik358n3mc-solana-labs.vercel.app

Built with commit 898b352.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.