This commit is contained in:
Armani Ferrante 2022-02-18 18:34:20 -05:00
parent 3cbf74cace
commit bb9b35acbc
No known key found for this signature in database
GPG Key ID: D597A80BCF8E12B7
13 changed files with 78 additions and 79 deletions

1
Cargo.lock generated
View File

@ -252,6 +252,7 @@ dependencies = [
"anyhow",
"arrayref",
"bs58 0.3.1",
"cargo_toml",
"heck 0.3.3",
"proc-macro2 1.0.32",
"proc-macro2-diagnostics",

View File

@ -83,10 +83,10 @@ impl Manifest {
}
pub fn version(&self) -> String {
match &self.package {
Some(package) => package.version.to_string(),
_ => "0.0.0".to_string(),
}
self.package
.as_ref()
.map(|p| p.version.clone())
.expect("Cargo.toml must have package version")
}
// Climbs each parent directory from the current dir until we find a Cargo.toml
@ -161,10 +161,9 @@ impl WithPath<Config> {
for path in self.get_program_list()? {
let cargo = Manifest::from_path(&path.join("Cargo.toml"))?;
let lib_name = cargo.lib_name()?;
let version = cargo.version();
let idl = anchor_syn::idl::file::parse(
&*cargo,
path.join("src/lib.rs"),
version,
self.features.seeds,
false,
)?;

View File

@ -1389,8 +1389,8 @@ fn extract_idl(cfg: &WithPath<Config>, file: &str) -> Result<Option<Idl>> {
let cargo = Manifest::discover_from_path(manifest_from_path)?
.ok_or_else(|| anyhow!("Cargo.toml not found"))?;
anchor_syn::idl::file::parse(
&*cargo,
&*file,
cargo.version(),
cfg.features.seeds,
cfg.features.safety_checks,
)

View File

@ -17,6 +17,7 @@ seeds = []
[dependencies]
arrayref = "0.3.6"
cargo_toml = "0.9.2"
proc-macro2 = { version = "1.0", features=["span-locations"]}
proc-macro2-diagnostics = "0.9"
quote = "1.0"

View File

@ -4,6 +4,7 @@ use crate::parser::{self, accounts, error, program};
use crate::Ty;
use crate::{AccountField, AccountsStruct, StateIx};
use anyhow::Result;
use cargo_toml::Manifest;
use heck::MixedCase;
use quote::ToTokens;
use std::collections::{HashMap, HashSet};
@ -15,8 +16,8 @@ const ERROR_CODE_OFFSET: u32 = 6000;
// Parse an entire interface file.
pub fn parse(
cargo: &Manifest,
filename: impl AsRef<Path>,
version: String,
seeds_feature: bool,
safety_checks: bool,
) -> Result<Option<Idl>> {
@ -241,8 +242,30 @@ pub fn parse(
})
.collect::<Vec<IdlConst>>();
let version = cargo
.package
.as_ref()
.map(|p| p.version.clone())
.expect("Cargo.toml must have package version");
let layout_version = {
let is_deprecated_layout = cargo
.dependencies
.get("anchor-lang")
.unwrap()
.req_features()
.iter()
.find(|f| f.as_str() == "deprecated-layout")
.is_some();
if is_deprecated_layout {
None
} else {
Some("0.1.0".to_string())
}
};
Ok(Some(Idl {
layout_version: "0.1.0".to_string(),
layout_version,
version,
name: p.name.to_string(),
state,

View File

@ -8,7 +8,8 @@ pub mod pda;
#[serde(rename_all = "camelCase")]
pub struct Idl {
// Version of the idl protocol.
pub layout_version: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub layout_version: Option<String>,
// Version of the program.
pub version: String,
pub name: String,

View File

@ -9,4 +9,4 @@ module.exports = async function (provider) {
anchor.setProvider(provider);
// Add your deploy script here.
}
};

View File

@ -1,6 +1,6 @@
import * as assert from "assert";
import * as anchor from '@project-serum/anchor';
import { Program, BorshAccountHeader } from '@project-serum/anchor';
import * as anchor from "@project-serum/anchor";
import { Program, BorshAccountHeader } from "@project-serum/anchor";
import { Keypair } from "@solana/web3.js";
import { DeprecatedLayout } from "../target/types/deprecated_layout";
import { NewLayout } from "../target/types/new_layout";
@ -10,8 +10,6 @@ describe("deprecated-layout", () => {
anchor.setProvider(anchor.Provider.env());
it("Has an 8 byte discriminator", async () => {
anchor.utils.features.set("deprecated-layout");
const program = anchor.workspace
.DeprecatedLayout as Program<DeprecatedLayout>;
@ -27,7 +25,9 @@ describe("deprecated-layout", () => {
const data = accountInfo.data;
const header = data.slice(0, 8);
const accountData = data.slice(8);
const expectedDiscriminator = BorshAccountHeader.discriminator("data");
const expectedDiscriminator = new BorshAccountHeader(
program.idl
).discriminator("data");
assert.ok(
"0xce9c3bbc124ff0e8" ===
@ -39,21 +39,9 @@ describe("deprecated-layout", () => {
const dataAccount = await program.account.data.fetch(dataKeypair.publicKey);
assert.ok(dataAccount.data.toNumber() === 2);
assert.rejects(
async () => {
anchor.utils.features.unset("deprecated-layout");
await program.account.data.fetch(dataKeypair.publicKey);
},
(err) => {
return err.toString() === "Error: Invalid account discriminator";
}
);
});
it("Has a 4 byte discriminator and 8 byte header", async () => {
anchor.utils.features.unset("deprecated-layout");
const program = anchor.workspace.NewLayout as Program<NewLayout>;
const dataKeypair = Keypair.generate();
@ -69,7 +57,9 @@ describe("deprecated-layout", () => {
const header = data.slice(0, 8);
const givenDiscriminator = header.slice(2, 6);
const accountData = data.slice(8);
const expectedDiscriminator = BorshAccountHeader.discriminator("data");
const expectedDiscriminator = new BorshAccountHeader(
program.idl
).discriminator("data");
assert.ok(
"0xce9c3bbc" === anchor.utils.bytes.hex.encode(expectedDiscriminator)
@ -84,15 +74,5 @@ describe("deprecated-layout", () => {
const dataAccount = await program.account.data.fetch(dataKeypair.publicKey);
assert.ok(dataAccount.data.toNumber() === 2);
assert.rejects(
async () => {
anchor.utils.features.set("deprecated-layout");
await program.account.data.fetch(dataKeypair.publicKey);
},
(err) => {
return err.toString() === "Error: Invalid account discriminator";
}
);
});
});

View File

@ -8,7 +8,6 @@ import { Idl, IdlTypeDef } from "../../idl.js";
import { IdlCoder } from "./idl.js";
import { AccountsCoder } from "../index.js";
import { accountSize } from "../common.js";
import { FeatureSet } from "../../utils/features";
/**
* Number of bytes of the account header.
@ -34,14 +33,14 @@ export class BorshAccountsCoder<A extends string = string>
/**
* IDL whose acconts will be coded.
*/
private idl: Idl;
private idl: Idl;
/**
* Header configuration.
*/
readonly header: BorshAccountHeader;
/**
* Header configuration.
*/
private header: BorshAccountHeader;
public constructor(idl: Idl) {
public constructor(idl: Idl) {
if (idl.accounts === undefined) {
this.accountLayouts = new Map();
return;
@ -52,7 +51,7 @@ export class BorshAccountsCoder<A extends string = string>
this.accountLayouts = new Map(layouts);
this.idl = idl;
this.header = new BorshAccountHeader(idl);
this.header = new BorshAccountHeader(idl);
}
public async encode<T = any>(accountName: A, account: T): Promise<Buffer> {
@ -105,14 +104,13 @@ export class BorshAccountsCoder<A extends string = string>
}
export class BorshAccountHeader {
constructor(_idl: Idl) {}
constructor(private _idl: Idl) {}
/**
* Returns the default account header for an account with the given name.
*/
public encode(accountName: string, nameSpace?: string): Buffer {
if (this._features.deprecatedLayout) {
if (this._idl.layoutVersion === undefined) {
return this.discriminator(accountName, nameSpace);
} else {
return Buffer.concat([
@ -138,7 +136,7 @@ export class BorshAccountHeader {
}
public discriminatorSize(): number {
return this._features.deprecatedLayout
return this._idl.layoutVersion === undefined
? DEPRECATED_ACCOUNT_DISCRIMINATOR_SIZE
: ACCOUNT_DISCRIMINATOR_SIZE;
}
@ -147,7 +145,7 @@ export class BorshAccountHeader {
* Returns the account data index at which the discriminator starts.
*/
public discriminatorOffset(): number {
if (this._features.deprecatedLayout) {
if (this._idl.layoutVersion === undefined) {
return 0;
} else {
return 2;
@ -165,7 +163,7 @@ export class BorshAccountHeader {
* Returns the discriminator from the given account data.
*/
public parseDiscriminator(data: Buffer): Buffer {
if (this._features.deprecatedLayout) {
if (this._idl.layoutVersion === undefined) {
return data.slice(0, 8);
} else {
return data.slice(2, 6);

View File

@ -6,7 +6,6 @@ import { Idl, IdlEvent, IdlTypeDef } from "../../idl.js";
import { Event, EventData } from "../../program/event.js";
import { IdlCoder } from "./idl.js";
import { EventCoder } from "../index.js";
import { FeatureSet } from "../../utils/features";
export class BorshEventCoder implements EventCoder {
/**
@ -19,17 +18,17 @@ export class BorshEventCoder implements EventCoder {
*/
private discriminators: Map<string, string>;
/**
* Header configuration.
*/
private header: EventHeader;
/**
* Header configuration.
*/
private header: EventHeader;
public constructor(idl: Idl) {
if (idl.events === undefined) {
this.layouts = new Map();
return;
}
this.header = new EventHeader(features);
this.header = new EventHeader(idl);
const layouts: [string, Layout<any>][] = idl.events.map((event) => {
let eventTypeDef: IdlTypeDef = {
name: event.name,
@ -89,10 +88,10 @@ export function eventDiscriminator(name: string): Buffer {
}
class EventHeader {
constructor(private _features: FeatureSet) {}
constructor(private _idl: Idl) {}
public parseDiscriminator(data: Buffer): Buffer {
if (this._features.deprecatedLayout) {
if (this._idl.layoutVersion === undefined) {
return data.slice(0, 8);
} else {
return data.slice(0, 4);
@ -100,7 +99,7 @@ class EventHeader {
}
public size(): number {
if (this._features.deprecatedLayout) {
if (this._idl.layoutVersion === undefined) {
return 8;
} else {
return 4;
@ -108,7 +107,7 @@ class EventHeader {
}
public discriminator(name: string): Buffer {
if (this._features.deprecatedLayout) {
if (this._idl.layoutVersion === undefined) {
return Buffer.from(sha256.digest(`event:${name}`)).slice(0, 8);
} else {
return Buffer.from(sha256.digest(`event:${name}`)).slice(0, 4);

View File

@ -3,19 +3,19 @@ import { Layout } from "buffer-layout";
import { sha256 } from "js-sha256";
import { Idl } from "../../idl.js";
import { IdlCoder } from "./idl.js";
import * as features from '../../utils/features';
import * as features from "../../utils/features";
import { BorshAccountHeader } from "./accounts";
export class BorshStateCoder {
private layout: Layout;
private header: BorshAccountHeader;
readonly header: BorshAccountHeader;
public constructor(idl: Idl, header: BorshAccountHeader) {
public constructor(idl: Idl) {
if (idl.state === undefined) {
throw new Error("Idl state not defined.");
}
this.layout = IdlCoder.typeDefLayout(idl.state.struct, idl.types);
this.header = header;
this.header = new BorshAccountHeader(idl);
}
public async encode<T = any>(name: string, account: T): Promise<Buffer> {

View File

@ -36,7 +36,7 @@ export default class StateFactory {
if (idl.state === undefined) {
return undefined;
}
return new StateClient(idl, programId, provider, coder);
return new StateClient(idl, programId, provider, coder as BorshCoder);
}
}
@ -74,7 +74,6 @@ export class StateClient<IDL extends Idl> {
private _programId: PublicKey;
private _address: PublicKey;
private _coder: Coder;
private _idl: IDL;
private _sub: Subscription | null;
@ -88,7 +87,7 @@ export class StateClient<IDL extends Idl> {
/**
* Returns the coder.
*/
public readonly coder: Coder = new BorshCoder(idl)
public readonly coder: BorshCoder = new BorshCoder(idl)
) {
this._idl = idl;
this._programId = programId;
@ -175,7 +174,7 @@ export class StateClient<IDL extends Idl> {
}
const expectedDiscriminator = await stateDiscriminator(state.struct.name);
const discriminator = BorshAccountHeader.parseDiscriminator(
const discriminator = this.coder.state.header.parseDiscriminator(
accountInfo.data
);
if (discriminator.compare(expectedDiscriminator)) {

View File

@ -1,16 +1,8 @@
export const Features = {
DeprecatedState: "anchor-deprecated-state",
DebugLogs: "debug-logs",
DeprecatedLayout: "deprecated-layout",
};
const _AVAILABLE_FEATURES = new Set([
Features.DeprecatedState,
Features.DebugLogs,
Features.DeprecatedLayout,
]);
const _FEATURES = new Map();
export function set(key: string) {
if (!_AVAILABLE_FEATURES.has(key)) {
throw new Error("Invalid feature");
@ -28,3 +20,9 @@ export function unset(key: string) {
export function isSet(key: string): boolean {
return _FEATURES.get(key) === true;
}
const _AVAILABLE_FEATURES = new Set([
Features.DeprecatedState,
Features.DebugLogs,
]);
const _FEATURES = new Map();