Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add source code url and fix --commit-hash bug #406

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions app/components/account/VerifiedBuildCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UpgradeableLoaderAccountData } from '@providers/accounts';
import { PublicKey } from '@solana/web3.js';
import { ExternalLink } from 'react-feather';

import { OsecRegistryInfo, useVerifiedProgramRegistry } from '@/app/utils/verified-builds';
import { OsecRegistryInfo, useVerifiedProgramRegistry, VerificationStatus } from '@/app/utils/verified-builds';

import { Copyable } from '../common/Copyable';
import { LoadingCard } from '../common/LoadingCard';
Expand All @@ -27,11 +27,21 @@ export function VerifiedBuildCard({ data, pubkey }: { data: UpgradeableLoaderAcc
return <ErrorCard text="No verified build found" />;
}

// Define the message based on the verification status
let verificationMessage = 'Information provided by osec.io';
if (registryInfo.verification_status === VerificationStatus.Verified) {
verificationMessage = 'Information provided by osec.io';
} else if (registryInfo.verification_status === VerificationStatus.PdaUploaded) {
verificationMessage = 'Information provided by the program deployer.';
} else if (registryInfo.verification_status === VerificationStatus.NotVerified) {
verificationMessage = 'No verified build found';
}

return (
<div className="card security-txt">
<div className="card-header">
<h3 className="card-header-title mb-0 d-flex align-items-center">Verified Build</h3>
<small>Information provided by osec.io</small>
<small>{verificationMessage}</small>
</div>
<div className="alert mt-2 mb-2">
Verified builds indicate that the onchain build was built from the source code that is publicly
Expand Down Expand Up @@ -76,8 +86,8 @@ type TableRow = {
const ROWS: TableRow[] = [
{
display: 'Verified',
key: 'is_verified',
type: DisplayType.Boolean,
key: 'verification_status',
type: DisplayType.String,
},
{
display: 'Message',
Expand Down Expand Up @@ -120,6 +130,15 @@ function RenderEntry({ value, type }: { value: OsecRegistryInfo[keyof OsecRegist
</td>
);
case DisplayType.String:
if (Object.values(VerificationStatus).includes(value as VerificationStatus)) {
const badgeClass = value === VerificationStatus.Verified ? 'bg-success-soft' : 'bg-warning-soft';
const badgeValue = value === VerificationStatus.Verified ? 'true' : 'false';
return (
<td className="text-lg-end font-monospace">
<span className={`badge ${badgeClass}`}>{badgeValue}</span>
</td>
);
}
return (
<td className="text-lg-end font-monospace" style={{ whiteSpace: 'pre' }}>
{value && (value as string).length > 1 ? value : '-'}
Expand Down
34 changes: 27 additions & 7 deletions app/components/common/VerifiedProgramBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PublicKey } from '@solana/web3.js';
import Link from 'next/link';

import { useClusterPath } from '@/app/utils/url';
import { hashProgramData, useVerifiedProgramRegistry } from '@/app/utils/verified-builds';
import { useVerifiedProgramRegistry, VerificationStatus } from '@/app/utils/verified-builds';
import { ProgramDataAccountInfo } from '@/app/validators/accounts/upgradeable-program';

export function VerifiedProgramBadge({
Expand All @@ -12,22 +12,42 @@ export function VerifiedProgramBadge({
programData: ProgramDataAccountInfo;
pubkey: PublicKey;
}) {
const { isLoading, data: registryInfo } = useVerifiedProgramRegistry({ programAuthority: programData.authority ? new PublicKey(programData.authority) : null, programId: pubkey });
const { isLoading, data: registryInfo } = useVerifiedProgramRegistry({
programAuthority: programData.authority ? new PublicKey(programData.authority) : null,
programData: programData,
programId: pubkey,
});
const verifiedBuildTabPath = useClusterPath({ pathname: `/address/${pubkey.toBase58()}/verified-build` });

const hash = hashProgramData(programData);

if (isLoading) {
return (
<h3 className="mb-0">
<span className="badge">Loading...</span>
</h3>
);
} else if (registryInfo && hash === registryInfo['on_chain_hash'] && registryInfo['is_verified']) {
} else if (registryInfo) {
let badgeClass = '';
let badgeText = '';

switch (registryInfo.verification_status) {
case VerificationStatus.Verified:
badgeClass = 'bg-success-soft';
badgeText = 'Program Source Verified';
break;
case VerificationStatus.PdaUploaded:
badgeClass = 'bg-warning-soft';
badgeText = 'Not verified';
break;
case VerificationStatus.NotVerified:
badgeClass = 'bg-warning-soft';
badgeText = 'Not verified';
break;
}

return (
<h3 className="mb-0">
<Link className="badge bg-success-soft rank" href={verifiedBuildTabPath}>
Program Source Program Verified
<Link className={`c-pointer badge ${badgeClass} rank`} href={verifiedBuildTabPath}>
{badgeText}
</Link>
</h3>
);
Expand Down
35 changes: 31 additions & 4 deletions app/utils/verified-builds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ import { Cluster } from './cluster';
const OSEC_REGISTRY_URL = 'https://verify.osec.io';
const VERIFY_PROGRAM_ID = 'verifycLy8mB96wd9wqq3WDXQwM4oU6r42Th37Db9fC';

export enum VerificationStatus {
Verified = 'Verified Build',
PdaUploaded = 'Not verified Build',
NotVerified = 'Not Verified',
}

export type OsecRegistryInfo = {
is_verified: boolean;
verification_status: VerificationStatus;
message: string;
on_chain_hash: string;
executable_hash: string;
Expand All @@ -24,10 +30,12 @@ export function useVerifiedProgramRegistry({
programId,
programAuthority,
options,
programData,
}: {
programId: PublicKey;
programAuthority: PublicKey | null;
options?: { suspense: boolean };
programData?: ProgramDataAccountInfo;
}) {
const { url: clusterUrl, cluster: cluster } = useCluster();
const connection = new Connection(clusterUrl);
Expand All @@ -40,11 +48,18 @@ export function useVerifiedProgramRegistry({
`${programId.toBase58()}`,
async (programId: string) => {
const response = await fetch(`${OSEC_REGISTRY_URL}/status/${programId}`);

return response.json();
},
{ suspense: options?.suspense }
);

if (programData && registryData) {
const hash = hashProgramData(programData);
registryData.verification_status =
hash === registryData['on_chain_hash'] ? VerificationStatus.Verified : VerificationStatus.NotVerified;
}

const { program: accountAnchorProgram } = useAnchorProgram(VERIFY_PROGRAM_ID, connection.rpcEndpoint);

// Fetch the PDA derived from the program upgrade authority
Expand All @@ -56,8 +71,12 @@ export function useVerifiedProgramRegistry({
} = useSWRImmutable(
programAuthority && accountAnchorProgram ? `pda-${programId.toBase58()}` : null,
async () => {
if (!programAuthority) {
console.log('Program authority not defined');
return null;
}
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from('otter_verify'), programAuthority!.toBuffer(), programId.toBuffer()],
[Buffer.from('otter_verify'), programAuthority.toBuffer(), programId.toBuffer()],
new PublicKey(VERIFY_PROGRAM_ID)
);
const pdaAccountInfo = await connection.getAccountInfo(pda);
Expand All @@ -81,7 +100,11 @@ export function useVerifiedProgramRegistry({
const verifiedData = registryData as OsecRegistryInfo;
verifiedData.verify_command = `solana-verify verify-from-repo -um --program-id ${programId.toBase58()} ${
pdaData.gitUrl
} --commit-hash ${pdaData.commit}`;
}`;

if (pdaData.commit) {
verifiedData.verify_command += ` --commit-hash ${pdaData.commit}`;
}

// Add additional args if available, for example mount-path and --library-name
if (pdaData.args && pdaData.args.length > 0) {
Expand All @@ -102,7 +125,11 @@ export function useVerifiedProgramRegistry({
verifiedData.verify_command += ` ${argsString}`;
}
}

verifiedData.repo_url = pdaData.gitUrl;
if (registryData.verification_status === VerificationStatus.NotVerified) {
verifiedData.message = 'Verify command was provided by the program authority.';
verifiedData.verification_status = VerificationStatus.PdaUploaded;
}
return { data: verifiedData, isLoading };
}
if (registryData && pdaData == null && !isLoading) {
Expand Down
Loading