explorer: display slot leaders on block details page (#24727)
This commit is contained in:
parent
f22738fd7b
commit
4e2d96fe88
|
@ -14,6 +14,7 @@ import { BlockProgramsCard } from "./BlockProgramsCard";
|
|||
import { BlockAccountsCard } from "./BlockAccountsCard";
|
||||
import { displayTimestamp, displayTimestampUtc } from "utils/date";
|
||||
import { Epoch } from "components/common/Epoch";
|
||||
import { Address } from "components/common/Address";
|
||||
|
||||
export function BlockOverviewCard({
|
||||
slot,
|
||||
|
@ -43,7 +44,8 @@ export function BlockOverviewCard({
|
|||
return <ErrorCard retry={refresh} text={`Block ${slot} was not found`} />;
|
||||
}
|
||||
|
||||
const block = confirmedBlock.data.block;
|
||||
const { block, blockLeader, childSlot, childLeader, parentLeader } =
|
||||
confirmedBlock.data;
|
||||
const committedTxs = block.transactions.filter((tx) => tx.meta?.err === null);
|
||||
const epoch = clusterInfo?.epochSchedule.getEpoch(slot);
|
||||
|
||||
|
@ -56,18 +58,26 @@ export function BlockOverviewCard({
|
|||
</h3>
|
||||
</div>
|
||||
<TableCardBody>
|
||||
<tr>
|
||||
<td className="w-100">Slot</td>
|
||||
<td className="text-lg-end font-monospace">
|
||||
<Slot slot={slot} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="w-100">Blockhash</td>
|
||||
<td className="text-lg-end font-monospace">
|
||||
<span>{block.blockhash}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="w-100">Slot</td>
|
||||
<td className="text-lg-end font-monospace">
|
||||
<Slot slot={slot} />
|
||||
</td>
|
||||
</tr>
|
||||
{blockLeader !== undefined && (
|
||||
<tr>
|
||||
<td className="w-100">Slot Leader</td>
|
||||
<td className="text-lg-end">
|
||||
<Address pubkey={blockLeader} alignRight link />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{block.blockTime ? (
|
||||
<>
|
||||
<tr>
|
||||
|
@ -93,12 +103,6 @@ export function BlockOverviewCard({
|
|||
<td className="text-lg-end">Unavailable</td>
|
||||
</tr>
|
||||
)}
|
||||
<tr>
|
||||
<td className="w-100">Parent Slot</td>
|
||||
<td className="text-lg-end font-monospace">
|
||||
<Slot slot={block.parentSlot} link />
|
||||
</td>
|
||||
</tr>
|
||||
{epoch !== undefined && (
|
||||
<tr>
|
||||
<td className="w-100">Epoch</td>
|
||||
|
@ -113,11 +117,33 @@ export function BlockOverviewCard({
|
|||
<span>{block.previousBlockhash}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{confirmedBlock.data.child && (
|
||||
<tr>
|
||||
<td className="w-100">Parent Slot</td>
|
||||
<td className="text-lg-end font-monospace">
|
||||
<Slot slot={block.parentSlot} link />
|
||||
</td>
|
||||
</tr>
|
||||
{parentLeader !== undefined && (
|
||||
<tr>
|
||||
<td className="w-100">Parent Slot Leader</td>
|
||||
<td className="text-lg-end">
|
||||
<Address pubkey={parentLeader} alignRight link />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{childSlot !== undefined && (
|
||||
<tr>
|
||||
<td className="w-100">Child Slot</td>
|
||||
<td className="text-lg-end font-monospace">
|
||||
<Slot slot={confirmedBlock.data.child} link />
|
||||
<Slot slot={childSlot} link />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{childLeader !== undefined && (
|
||||
<tr>
|
||||
<td className="w-100">Child Slot Leader</td>
|
||||
<td className="text-lg-end">
|
||||
<Address pubkey={childLeader} alignRight link />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import * as Cache from "providers/cache";
|
||||
import { Connection, BlockResponse } from "@solana/web3.js";
|
||||
import { Connection, BlockResponse, PublicKey } from "@solana/web3.js";
|
||||
import { useCluster, Cluster } from "./cluster";
|
||||
|
||||
export enum FetchStatus {
|
||||
|
@ -17,7 +17,10 @@ export enum ActionType {
|
|||
|
||||
type Block = {
|
||||
block?: BlockResponse;
|
||||
child?: number;
|
||||
blockLeader?: PublicKey;
|
||||
childSlot?: number;
|
||||
childLeader?: PublicKey;
|
||||
parentLeader?: PublicKey;
|
||||
};
|
||||
|
||||
type State = Cache.State<Block>;
|
||||
|
@ -59,12 +62,12 @@ export async function fetchBlock(
|
|||
dispatch: Dispatch,
|
||||
url: string,
|
||||
cluster: Cluster,
|
||||
key: number
|
||||
slot: number
|
||||
) {
|
||||
dispatch({
|
||||
type: ActionType.Update,
|
||||
status: FetchStatus.Fetching,
|
||||
key,
|
||||
key: slot,
|
||||
url,
|
||||
});
|
||||
|
||||
|
@ -73,13 +76,39 @@ export async function fetchBlock(
|
|||
|
||||
try {
|
||||
const connection = new Connection(url, "confirmed");
|
||||
const block = await connection.getBlock(key);
|
||||
const child = (await connection.getBlocks(key + 1, key + 100)).shift();
|
||||
const block = await connection.getBlock(slot);
|
||||
if (block === null) {
|
||||
data = {};
|
||||
status = FetchStatus.Fetched;
|
||||
} else {
|
||||
data = { block, child };
|
||||
const childSlot = (
|
||||
await connection.getBlocks(slot + 1, slot + 100)
|
||||
).shift();
|
||||
const firstLeaderSlot = block.parentSlot;
|
||||
|
||||
let leaders: PublicKey[] = [];
|
||||
try {
|
||||
const lastLeaderSlot = childSlot !== undefined ? childSlot : slot;
|
||||
const slotLeadersLimit = lastLeaderSlot - block.parentSlot + 1;
|
||||
leaders = await connection.getSlotLeaders(
|
||||
firstLeaderSlot,
|
||||
slotLeadersLimit
|
||||
);
|
||||
} catch (err) {
|
||||
// ignore errors
|
||||
}
|
||||
|
||||
const getLeader = (slot: number) => {
|
||||
return leaders.at(slot - firstLeaderSlot);
|
||||
};
|
||||
|
||||
data = {
|
||||
block,
|
||||
blockLeader: getLeader(slot),
|
||||
childSlot,
|
||||
childLeader: childSlot !== undefined ? getLeader(childSlot) : undefined,
|
||||
parentLeader: getLeader(block.parentSlot),
|
||||
};
|
||||
status = FetchStatus.Fetched;
|
||||
}
|
||||
} catch (err) {
|
||||
|
@ -92,7 +121,7 @@ export async function fetchBlock(
|
|||
dispatch({
|
||||
type: ActionType.Update,
|
||||
url,
|
||||
key,
|
||||
key: slot,
|
||||
status,
|
||||
data,
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue