Skip to content

Commit

Permalink
ts: verified build utility (coral-xyz#1371)
Browse files Browse the repository at this point in the history
  • Loading branch information
armaniferrante authored and losman0s committed Feb 7, 2022
1 parent 3ab4210 commit 522daf7
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -17,6 +17,7 @@ incremented for features.
* lang: `Context` now has a new `bumps: BTree<String, u8>` argument, mapping account name to bump seed "found" by the accounts context. This allows one to access bump seeds without having to pass them in from the client or recalculate them in the handler ([#1367](calculated )).
* ts: Remove error logging in the event parser when log websocket encounters a program error ([#1313](https://github.com/project-serum/anchor/pull/1313)).
* ts: Add new `methods` namespace to the program client, introducing a more ergonomic builder API ([#1324](https://github.com/project-serum/anchor/pull/1324)).
* ts: Add registry utility for fetching the latest verified build ([#1371](https://github.com/project-serum/anchor/pull/1371)).

### Breaking

Expand Down
3 changes: 2 additions & 1 deletion ts/package.json
Expand Up @@ -33,13 +33,14 @@
"test": "jest tests --detectOpenHandles"
},
"dependencies": {
"@project-serum/borsh": "^0.2.2",
"@project-serum/borsh": "^0.2.4",
"@solana/web3.js": "^1.17.0",
"base64-js": "^1.5.1",
"bn.js": "^5.1.2",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.2",
"camelcase": "^5.3.1",
"cross-fetch": "^3.1.5",
"crypto-hash": "^1.3.0",
"eventemitter3": "^4.0.7",
"find": "^0.3.0",
Expand Down
1 change: 1 addition & 0 deletions ts/src/utils/index.ts
Expand Up @@ -4,3 +4,4 @@ export * as publicKey from "./pubkey.js";
export * as bytes from "./bytes/index.js";
export * as token from "./token.js";
export * as features from "./features.js";
export * as registry from "./registry.js";
110 changes: 110 additions & 0 deletions ts/src/utils/registry.ts
@@ -0,0 +1,110 @@
import BN from "bn.js";
import fetch from "cross-fetch";
import * as borsh from "@project-serum/borsh";
import { Connection, PublicKey } from "@solana/web3.js";

/**
* Returns a verified build from the anchor registry. null if no such
* verified build exists, e.g., if the program has been upgraded since the
* last verified build.
*/
export async function verifiedBuild(
connection: Connection,
programId: PublicKey,
limit: number = 5
): Promise<Build | null> {
const url = `https://anchor.projectserum.com/api/v0/program/${programId.toString()}/latest?limit=${limit}`;
const [programData, latestBuildsResp] = await Promise.all([
fetchData(connection, programId),
fetch(url),
]);

// Filter out all non successful builds.
const latestBuilds = (await latestBuildsResp.json()).filter(
(b: Build) => !b.aborted && b.state === "Built" && b.verified === "Verified"
);
if (latestBuilds.length === 0) {
return null;
}

// Get the latest build.
const build = latestBuilds[0];

// Has the program been upgraded since the last build?
if (programData.slot.toNumber() !== build.verified_slot) {
return null;
}

// Success.
return build;
}

/**
* Returns the program data account for this program, containing the
* metadata for this program, e.g., the upgrade authority.
*/
export async function fetchData(
connection: Connection,
programId: PublicKey
): Promise<ProgramData> {
const accountInfo = await connection.getAccountInfo(programId);
if (accountInfo === null) {
throw new Error("program account not found");
}
const { program } = decodeUpgradeableLoaderState(accountInfo.data);
const programdataAccountInfo = await connection.getAccountInfo(
program.programdataAddress
);
if (programdataAccountInfo === null) {
throw new Error("program data account not found");
}
const { programData } = decodeUpgradeableLoaderState(
programdataAccountInfo.data
);
return programData;
}

const UPGRADEABLE_LOADER_STATE_LAYOUT = borsh.rustEnum(
[
borsh.struct([], "uninitialized"),
borsh.struct(
[borsh.option(borsh.publicKey(), "authorityAddress")],
"buffer"
),
borsh.struct([borsh.publicKey("programdataAddress")], "program"),
borsh.struct(
[
borsh.u64("slot"),
borsh.option(borsh.publicKey(), "upgradeAuthorityAddress"),
],
"programData"
),
],
undefined,
borsh.u32()
);

export function decodeUpgradeableLoaderState(data: Buffer): any {
return UPGRADEABLE_LOADER_STATE_LAYOUT.decode(data);
}

export type ProgramData = {
slot: BN;
upgradeAuthorityAddress: PublicKey | null;
};

export type Build = {
aborted: boolean;
address: string;
created_at: string;
updated_at: string;
descriptor: string[];
docker: string;
id: number;
name: string;
sha256: string;
upgrade_authority: string;
verified: string;
verified_slot: number;
state: string;
};
40 changes: 36 additions & 4 deletions ts/yarn.lock
Expand Up @@ -855,10 +855,10 @@
"@nodelib/fs.scandir" "2.1.4"
fastq "^1.6.0"

"@project-serum/borsh@^0.2.2":
version "0.2.2"
resolved "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.2.tgz"
integrity sha512-Ms+aWmGVW6bWd3b0+MWwoaYig2QD0F90h0uhr7AzY3dpCb5e2S6RsRW02vFTfa085pY2VLB7nTZNbFECQ1liTg==
"@project-serum/borsh@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.4.tgz#8884c3a759984a39d54bf5b7390bd1ee0b579f16"
integrity sha512-tQPc1ktAp1Jtn9D72DmObAfhAic9ivfYBOS5b+T4H7MvkQ84uML88LY1LfvGep30mCy+ua5rf+X9ocPfg6u9MA==
dependencies:
bn.js "^5.1.2"
buffer-layout "^1.2.0"
Expand Down Expand Up @@ -1836,6 +1836,13 @@ create-require@^1.1.0:
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==

cross-fetch@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
dependencies:
node-fetch "2.6.7"

cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
Expand Down Expand Up @@ -3744,6 +3751,13 @@ node-addon-api@^2.0.0:
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==

node-fetch@2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"

node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz"
Expand Down Expand Up @@ -4695,6 +4709,11 @@ tr46@^2.1.0:
dependencies:
punycode "^2.1.1"

tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=

traverse-chain@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
Expand Down Expand Up @@ -4929,6 +4948,11 @@ walker@^1.0.7:
dependencies:
makeerror "1.0.x"

webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=

webidl-conversions@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz"
Expand All @@ -4951,6 +4975,14 @@ whatwg-mimetype@^2.3.0:
resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==

whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"

whatwg-url@^8.0.0:
version "8.4.0"
resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz"
Expand Down

0 comments on commit 522daf7

Please sign in to comment.