explorer: Add block rewards to block details page (#14786)

* explorer: add block rewards

* add key to tr map
This commit is contained in:
Josh
2021-01-26 11:51:58 -08:00
committed by GitHub
parent 119e2c75dd
commit a395037671
4 changed files with 131 additions and 60 deletions

View File

@ -0,0 +1,65 @@
import React from "react";
import { ConfirmedBlock } from "@solana/web3.js";
import { ErrorCard } from "components/common/ErrorCard";
import { Signature } from "components/common/Signature";
import bs58 from "bs58";
export function BlockHistoryCard({ block }: { block: ConfirmedBlock }) {
if (block.transactions.length === 0) {
return <ErrorCard text="This block has no transactions" />;
}
return (
<div className="card">
<div className="card-header align-items-center">
<h3 className="card-header-title">Block Transactions</h3>
</div>
<div className="table-responsive mb-0">
<table className="table table-sm table-nowrap card-table">
<thead>
<tr>
<th className="text-muted">Result</th>
<th className="text-muted">Transaction Signature</th>
</tr>
</thead>
<tbody className="list">
{block.transactions.map((tx, i) => {
let statusText;
let statusClass;
let signature: React.ReactNode;
if (tx.meta?.err || !tx.transaction.signature) {
statusClass = "warning";
statusText = "Failed";
} else {
statusClass = "success";
statusText = "Success";
}
if (tx.transaction.signature) {
signature = (
<Signature
signature={bs58.encode(tx.transaction.signature)}
link
/>
);
}
return (
<tr key={i}>
<td>
<span className={`badge badge-soft-${statusClass}`}>
{statusText}
</span>
</td>
<td>{signature}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}

View File

@ -1,14 +1,14 @@
import bs58 from "bs58";
import React from "react"; import React from "react";
import { TableCardBody } from "components/common/TableCardBody"; import { TableCardBody } from "components/common/TableCardBody";
import { useBlock, useFetchBlock, FetchStatus } from "providers/block"; import { useBlock, useFetchBlock, FetchStatus } from "providers/block";
import { Signature } from "components/common/Signature";
import { ErrorCard } from "components/common/ErrorCard"; import { ErrorCard } from "components/common/ErrorCard";
import { LoadingCard } from "components/common/LoadingCard"; import { LoadingCard } from "components/common/LoadingCard";
import { Slot } from "components/common/Slot"; import { Slot } from "components/common/Slot";
import { ClusterStatus, useCluster } from "providers/cluster"; import { ClusterStatus, useCluster } from "providers/cluster";
import { BlockHistoryCard } from "./BlockHistoryCard";
import { BlockRewardsCard } from "./BlockRewardsCard";
export function BlockHistoryCard({ slot }: { slot: number }) { export function BlockOverviewCard({ slot }: { slot: number }) {
const confirmedBlock = useBlock(slot); const confirmedBlock = useBlock(slot);
const fetchBlock = useFetchBlock(); const fetchBlock = useFetchBlock();
const { status } = useCluster(); const { status } = useCluster();
@ -67,61 +67,8 @@ export function BlockHistoryCard({ slot }: { slot: number }) {
</TableCardBody> </TableCardBody>
</div> </div>
{block.transactions.length === 0 ? ( <BlockRewardsCard block={block} />
<ErrorCard text="This block has no transactions" /> <BlockHistoryCard block={block} />
) : (
<div className="card">
<div className="card-header align-items-center">
<h3 className="card-header-title">Block Transactions</h3>
</div>
<div className="table-responsive mb-0">
<table className="table table-sm table-nowrap card-table">
<thead>
<tr>
<th className="text-muted">Result</th>
<th className="text-muted">Transaction Signature</th>
</tr>
</thead>
<tbody className="list">
{block.transactions.map((tx, i) => {
let statusText;
let statusClass;
let signature: React.ReactNode;
if (tx.meta?.err || !tx.transaction.signature) {
statusClass = "warning";
statusText = "Failed";
} else {
statusClass = "success";
statusText = "Success";
}
if (tx.transaction.signature) {
signature = (
<Signature
signature={bs58.encode(tx.transaction.signature)}
link
/>
);
}
return (
<tr key={i}>
<td>
<span className={`badge badge-soft-${statusClass}`}>
{statusText}
</span>
</td>
<td>{signature}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
)}
</> </>
); );
} }

View File

@ -0,0 +1,59 @@
import React from "react";
import { lamportsToSolString } from "utils";
import { ConfirmedBlock, PublicKey } from "@solana/web3.js";
import { Address } from "components/common/Address";
export function BlockRewardsCard({ block }: { block: ConfirmedBlock }) {
if (block.rewards.length < 1) {
return null;
}
return (
<div className="card">
<div className="card-header align-items-center">
<h3 className="card-header-title">Block Rewards</h3>
</div>
<div className="table-responsive mb-0">
<table className="table table-sm table-nowrap card-table">
<thead>
<tr>
<th className="text-muted">Address</th>
<th className="text-muted">Type</th>
<th className="text-muted">Amount</th>
<th className="text-muted">New Balance</th>
<th className="text-muted">Percent Change</th>
</tr>
</thead>
<tbody>
{block.rewards.map((reward) => {
let percentChange;
if (reward.postBalance !== null && reward.postBalance !== 0) {
percentChange = (
(Math.abs(reward.lamports) /
(reward.postBalance - reward.lamports)) *
100
).toFixed(9);
}
return (
<tr key={reward.pubkey + reward.rewardType}>
<td>
<Address pubkey={new PublicKey(reward.pubkey)} link />
</td>
<td>{reward.rewardType}</td>
<td>{lamportsToSolString(reward.lamports)}</td>
<td>
{reward.postBalance
? lamportsToSolString(reward.postBalance)
: "-"}
</td>
<td>{percentChange ? percentChange + "%" : "-"}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { BlockHistoryCard } from "components/account/BlockHistoryCard";
import { ErrorCard } from "components/common/ErrorCard"; import { ErrorCard } from "components/common/ErrorCard";
import { BlockOverviewCard } from "components/block/BlockOverviewCard";
type Props = { slot: string }; type Props = { slot: string };
@ -9,7 +9,7 @@ export function BlockDetailsPage({ slot }: Props) {
let output = <ErrorCard text={`Block ${slot} is not valid`} />; let output = <ErrorCard text={`Block ${slot} is not valid`} />;
if (!isNaN(Number(slot))) { if (!isNaN(Number(slot))) {
output = <BlockHistoryCard slot={Number(slot)} />; output = <BlockOverviewCard slot={Number(slot)} />;
} }
return ( return (