update
This commit is contained in:
parent
3cbf74cace
commit
bb9b35acbc
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
)?;
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -9,4 +9,4 @@ module.exports = async function (provider) {
|
|||
anchor.setProvider(provider);
|
||||
|
||||
// Add your deploy script here.
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue