Armani Ferrante 3 tahun lalu
induk
melakukan
a8acf640c0

+ 1 - 1
lang/common/src/header.rs

@@ -41,7 +41,7 @@ pub fn read_data_mut(account_data: &mut [u8]) -> &mut [u8] {
 pub fn write_discriminator(account_data: &mut [u8], discriminator: &[u8]) {
     #[cfg(feature = "deprecated-layout")]
     {
-        let mut cursor = Cursor::new(account_dst);
+        let mut cursor = Cursor::new(account_data);
         cursor.write_all(discriminator).unwrap();
     }
     #[cfg(not(feature = "deprecated-layout"))]

+ 6 - 0
tests/deprecated-layout/.gitignore

@@ -0,0 +1,6 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules

+ 16 - 0
tests/deprecated-layout/Anchor.toml

@@ -0,0 +1,16 @@
+[features]
+seeds = false
+
+[programs.localnet]
+deprecated_layout = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
+new_layout = "9LA72twzmEHH6EH8oEiNnb2CsUdN9CqAtDNXCkj1c9Uw"
+
+[registry]
+url = "https://anchor.projectserum.com"
+
+[provider]
+cluster = "localnet"
+wallet = "/home/armaniferrante/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 4 - 0
tests/deprecated-layout/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "programs/*"
+]

+ 12 - 0
tests/deprecated-layout/migrations/deploy.ts

@@ -0,0 +1,12 @@
+// Migrations are an early feature. Currently, they're nothing more than this
+// single deploy script that's invoked from the CLI, injecting a provider
+// configured from the workspace's Anchor.toml.
+
+const anchor = require("@project-serum/anchor");
+
+module.exports = async function (provider) {
+  // Configure client to use the provider.
+  anchor.setProvider(provider);
+
+  // Add your deploy script here.
+}

+ 26 - 0
tests/deprecated-layout/package.json

@@ -0,0 +1,26 @@
+{
+  "name": "deprecated-layout",
+  "version": "0.21.0",
+  "license": "(MIT OR Apache-2.0)",
+  "homepage": "https://github.com/project-serum/anchor#readme",
+  "bugs": {
+    "url": "https://github.com/project-serum/anchor/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/project-serum/anchor.git"
+  },
+  "engines": {
+    "node": ">=11"
+  },
+  "dependencies": {
+    "@project-serum/anchor": "^0.21.0"
+  },
+  "devDependencies": {
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^8.0.0",
+    "@types/mocha": "^9.0.0",
+    "typescript": "^4.3.5"
+  }
+}

+ 19 - 0
tests/deprecated-layout/programs/deprecated-layout/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "deprecated-layout"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "deprecated_layout"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = { path = "../../../../lang", features = ["deprecated-layout"] }

+ 2 - 0
tests/deprecated-layout/programs/deprecated-layout/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 31 - 0
tests/deprecated-layout/programs/deprecated-layout/src/lib.rs

@@ -0,0 +1,31 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod deprecated_layout {
+    use super::*;
+
+    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
+        ctx.accounts.data.data = 2;
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Initialize<'info> {
+    #[account(
+				init,
+				payer = payer,
+				space = 16,
+		)]
+    data: Account<'info, Data>,
+    #[account(mut)]
+    payer: Signer<'info>,
+    system_program: Program<'info, System>,
+}
+
+#[account]
+pub struct Data {
+    data: u64,
+}

+ 19 - 0
tests/deprecated-layout/programs/new-layout/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "new-layout"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "new_layout"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }

+ 2 - 0
tests/deprecated-layout/programs/new-layout/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 31 - 0
tests/deprecated-layout/programs/new-layout/src/lib.rs

@@ -0,0 +1,31 @@
+use anchor_lang::prelude::*;
+
+declare_id!("9LA72twzmEHH6EH8oEiNnb2CsUdN9CqAtDNXCkj1c9Uw");
+
+#[program]
+pub mod new_layout {
+    use super::*;
+
+    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
+        ctx.accounts.data.data = 2;
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Initialize<'info> {
+    #[account(
+				init,
+				payer = payer,
+				space = 16,
+		)]
+    data: Account<'info, Data>,
+    #[account(mut)]
+    payer: Signer<'info>,
+    system_program: Program<'info, System>,
+}
+
+#[account]
+pub struct Data {
+    data: u64,
+}

+ 100 - 0
tests/deprecated-layout/tests/deprecated-layout.ts

@@ -0,0 +1,100 @@
+import * as assert from "assert";
+//import * as anchor from '@project-serum/anchor';
+//import { Program, BorshAccountHeader } from '@project-serum/anchor';
+import * as anchor from "../../../ts";
+import { Program, BorshAccountHeader } from "../../../ts";
+import { Keypair } from "@solana/web3.js";
+import { DeprecatedLayout } from "../target/types/deprecated_layout";
+import { NewLayout } from "../target/types/new_layout";
+
+describe("deprecated-layout", () => {
+  // Configure the client to use the local cluster.
+  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>;
+
+    const dataKeypair = Keypair.generate();
+    await program.methods
+      .initialize()
+      .accounts({ data: dataKeypair.publicKey })
+      .signers([dataKeypair])
+      .rpc();
+    const accountInfo = await program.account.data.getAccountInfo(
+      dataKeypair.publicKey
+    );
+    const data = accountInfo.data;
+    const header = data.slice(0, 8);
+    const accountData = data.slice(8);
+    const expectedDiscriminator = BorshAccountHeader.discriminator("data");
+
+    assert.ok(
+      "0xce9c3bbc124ff0e8" ===
+        anchor.utils.bytes.hex.encode(expectedDiscriminator)
+    );
+    assert.ok(expectedDiscriminator.length === 8);
+    assert.ok(header.compare(expectedDiscriminator) === 0);
+    assert.ok(accountData.compare(Buffer.from([2, 0, 0, 0, 0, 0, 0, 0])) === 0);
+
+    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();
+    await program.methods
+      .initialize()
+      .accounts({ data: dataKeypair.publicKey })
+      .signers([dataKeypair])
+      .rpc();
+    const accountInfo = await program.account.data.getAccountInfo(
+      dataKeypair.publicKey
+    );
+    const data = accountInfo.data;
+    const header = data.slice(0, 8);
+    const givenDiscriminator = header.slice(2, 6);
+    const accountData = data.slice(8);
+    const expectedDiscriminator = BorshAccountHeader.discriminator("data");
+
+    assert.ok(
+      "0xce9c3bbc" === anchor.utils.bytes.hex.encode(expectedDiscriminator)
+    );
+    assert.ok(expectedDiscriminator.length === 4);
+    assert.ok(givenDiscriminator.compare(expectedDiscriminator) === 0);
+    assert.ok(accountData.compare(Buffer.from([2, 0, 0, 0, 0, 0, 0, 0])) === 0);
+    assert.ok(header[0] === 0);
+    assert.ok(header[1] === 0);
+    assert.ok(header[6] === 0);
+    assert.ok(header[7] === 0);
+
+    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";
+      }
+    );
+  });
+});

+ 10 - 0
tests/deprecated-layout/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true
+  }
+}

+ 5 - 4
ts/src/coder/borsh/accounts.ts

@@ -9,6 +9,7 @@ import { IdlCoder } from "./idl.js";
 import { AccountsCoder } from "../index.js";
 import { accountSize } from "../common.js";
 import * as features from "../../utils/features";
+import { Features } from "../../utils/features";
 
 /**
  * Number of bytes of the account header.
@@ -103,7 +104,7 @@ export class BorshAccountHeader {
    * Returns the default account header for an account with the given name.
    */
   public static encode(accountName: string, nameSpace?: string): Buffer {
-    if (features.isSet("deprecated-layout")) {
+    if (features.isSet(Features.DeprecatedLayout)) {
       return BorshAccountHeader.discriminator(accountName, nameSpace);
     } else {
       return Buffer.concat([
@@ -129,7 +130,7 @@ export class BorshAccountHeader {
   }
 
   public static discriminatorSize(): number {
-    return features.isSet("deprecated-layout")
+    return features.isSet(Features.DeprecatedLayout)
       ? DEPRECATED_ACCOUNT_DISCRIMINATOR_SIZE
       : ACCOUNT_DISCRIMINATOR_SIZE;
   }
@@ -138,7 +139,7 @@ export class BorshAccountHeader {
    * Returns the account data index at which the discriminator starts.
    */
   public static discriminatorOffset(): number {
-    if (features.isSet("deprecated-layout")) {
+    if (features.isSet(Features.DeprecatedLayout)) {
       return 0;
     } else {
       return 2;
@@ -156,7 +157,7 @@ export class BorshAccountHeader {
    * Returns the discriminator from the given account data.
    */
   public static parseDiscriminator(data: Buffer): Buffer {
-    if (features.isSet("deprecated-layout")) {
+    if (features.isSet(Features.DeprecatedLayout)) {
       return data.slice(0, 8);
     } else {
       return data.slice(2, 6);

+ 4 - 3
ts/src/coder/borsh/event.ts

@@ -7,6 +7,7 @@ import { Event, EventData } from "../../program/event.js";
 import { IdlCoder } from "./idl.js";
 import { EventCoder } from "../index.js";
 import * as features from "../../utils/features";
+import { Features } from "../../utils/features";
 
 export class BorshEventCoder implements EventCoder {
   /**
@@ -84,7 +85,7 @@ export function eventDiscriminator(name: string): Buffer {
 
 class EventHeader {
   public static parseDiscriminator(data: Buffer): Buffer {
-    if (features.isSet("deprecated-layout")) {
+    if (features.isSet(Features.DeprecatedLayout)) {
       return data.slice(0, 8);
     } else {
       return data.slice(0, 4);
@@ -92,7 +93,7 @@ class EventHeader {
   }
 
   public static size(): number {
-    if (features.isSet("deprecated-layout")) {
+    if (features.isSet(Features.DeprecatedLayout)) {
       return 8;
     } else {
       return 4;
@@ -100,7 +101,7 @@ class EventHeader {
   }
 
   public static discriminator(name: string): Buffer {
-    if (features.isSet("deprecated-layout")) {
+    if (features.isSet(Features.DeprecatedLayout)) {
       return Buffer.from(sha256.digest(`event:${name}`)).slice(0, 8);
     } else {
       return Buffer.from(sha256.digest(`event:${name}`)).slice(0, 4);

+ 17 - 5
ts/src/utils/features.ts

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