Prechádzať zdrojové kódy

tests: Add remaining accounts test (#2683)

Pierre 1 rok pred
rodič
commit
9331908aee

+ 1 - 0
tests/misc/Anchor.toml

@@ -7,6 +7,7 @@ init_if_needed = "BZoppwWi6jMnydnUBEJzotgEXHwLr3b3NramJgZtWeF2"
 lamports = "Lamports11111111111111111111111111111111111"
 misc = "3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh"
 misc_optional = "FNqz6pqLAwvMSds2FYjR4nKV3moVpPNtvkfGFrqLKrgG"
+remaining_accounts = "RemainingAccounts11111111111111111111111111"
 
 [workspace]
 exclude = ["programs/shared"]

+ 2 - 2
tests/misc/programs/misc-optional/Cargo.toml

@@ -18,5 +18,5 @@ default = []
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
 anchor-spl = { path = "../../../../spl" }
-spl-associated-token-account = "1.1.1"
-bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]}
+spl-associated-token-account = { version = "1.1.1", features = ["no-entrypoint"] }
+bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] }

+ 2 - 2
tests/misc/programs/misc/Cargo.toml

@@ -18,5 +18,5 @@ default = []
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
 anchor-spl = { path = "../../../../spl" }
-spl-associated-token-account = "1.1.1"
-bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]}
+spl-associated-token-account = { version = "1.1.1", features = ["no-entrypoint"] }
+bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] }

+ 20 - 0
tests/misc/programs/remaining-accounts/Cargo.toml

@@ -0,0 +1,20 @@
+[package]
+name = "remaining-accounts"
+version = "0.1.0"
+description = "Created with Anchor"
+rust-version = "1.60"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "remaining_accounts"
+
+[features]
+no-entrypoint = []
+no-idl = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
+anchor-spl = { path = "../../../../spl" }

+ 2 - 0
tests/misc/programs/remaining-accounts/Xargo.toml

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

+ 11 - 0
tests/misc/programs/remaining-accounts/src/account.rs

@@ -0,0 +1,11 @@
+use anchor_lang::prelude::*;
+
+#[account]
+#[derive(InitSpace)]
+pub struct Data {
+    pub someone: Pubkey,
+}
+
+#[account]
+#[derive(InitSpace)]
+pub struct Another {}

+ 26 - 0
tests/misc/programs/remaining-accounts/src/context.rs

@@ -0,0 +1,26 @@
+use crate::account::*;
+use anchor_lang::prelude::*;
+use anchor_spl::token::Token;
+
+#[derive(Accounts)]
+pub struct TestInit<'info> {
+    #[account(init, payer = payer, space = Data::INIT_SPACE + 8)]
+    pub data: Account<'info, Data>,
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct TestInitAnother<'info> {
+    #[account(init, payer = payer, space = Data::INIT_SPACE + 8)]
+    pub another: Account<'info, Another>,
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct TestRemainingAccounts<'info> {
+    pub token_program: Program<'info, Token>,
+}

+ 42 - 0
tests/misc/programs/remaining-accounts/src/lib.rs

@@ -0,0 +1,42 @@
+//! Testing of handling of remaining accounts with anchor Account structs
+
+use account::*;
+use anchor_lang::prelude::*;
+use anchor_spl::token::TokenAccount;
+use context::*;
+
+mod account;
+mod context;
+
+declare_id!("RemainingAccounts11111111111111111111111111");
+
+#[program]
+pub mod remaining_accounts {
+    use super::*;
+
+    pub fn test_init(_ctx: Context<TestInit>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_init_another(_ctx: Context<TestInitAnother>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_remaining_accounts<'c: 'info, 'info>(
+        ctx: Context<'_, '_, 'c, 'info, TestRemainingAccounts>,
+    ) -> Result<()> {
+        let remaining_accounts_iter = &mut ctx.remaining_accounts.iter();
+
+        let token_account =
+            Account::<TokenAccount>::try_from(next_account_info(remaining_accounts_iter)?)?;
+
+        let data_account_info = next_account_info(remaining_accounts_iter)?;
+        require_eq!(data_account_info.is_writable, true);
+        let mut data = Account::<Data>::try_from(data_account_info)?;
+
+        data.someone = token_account.owner;
+        data.exit(ctx.program_id)?;
+
+        Ok(())
+    }
+}

+ 2 - 0
tests/misc/tests/remaining-accounts/Test.toml

@@ -0,0 +1,2 @@
+[scripts]
+test = "yarn run ts-mocha -t 1000000 ./tests/remaining-accounts/*.ts"

+ 111 - 0
tests/misc/tests/remaining-accounts/remaining-accounts.ts

@@ -0,0 +1,111 @@
+import * as anchor from "@coral-xyz/anchor";
+
+import { TOKEN_PROGRAM_ID, Token } from "@solana/spl-token";
+import { assert } from "chai";
+import { RemainingAccounts, IDL } from "../../target/types/remaining_accounts";
+import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
+
+describe(IDL.name, () => {
+  // Configure the client to use the local cluster
+  anchor.setProvider(anchor.AnchorProvider.env());
+  const payer = NodeWallet.local().payer;
+
+  const program = anchor.workspace
+    .RemainingAccounts as anchor.Program<RemainingAccounts>;
+
+  it("Account can be used with remaining accounts - read token account and write someone to Data", async () => {
+    const data = anchor.web3.Keypair.generate();
+    await program.methods
+      .testInit()
+      .accounts({ data: data.publicKey })
+      .signers([data])
+      .rpc();
+    const ata = await Token.createWrappedNativeAccount(
+      program.provider.connection,
+      TOKEN_PROGRAM_ID,
+      payer.publicKey,
+      payer,
+      0
+    );
+
+    // Data is not initialized
+    try {
+      await program.methods
+        .testRemainingAccounts()
+        .accounts({
+          tokenProgram: TOKEN_PROGRAM_ID,
+        })
+        .remainingAccounts([
+          { pubkey: ata, isSigner: false, isWritable: false },
+          {
+            pubkey: anchor.web3.Keypair.generate().publicKey,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .rpc();
+      assert.isTrue(false);
+    } catch (_err) {
+      assert.isTrue(_err instanceof anchor.AnchorError);
+      const err: anchor.AnchorError = _err;
+      assert.strictEqual(err.error.errorCode.number, 3012);
+      assert.strictEqual(err.error.errorCode.code, "AccountNotInitialized");
+    }
+
+    // Can read and write from account infos from remaining_accounts
+    await program.methods
+      .testRemainingAccounts()
+      .accounts({
+        tokenProgram: TOKEN_PROGRAM_ID,
+      })
+      .remainingAccounts([
+        { pubkey: ata, isSigner: false, isWritable: false },
+        {
+          pubkey: data.publicKey,
+          isSigner: false,
+          isWritable: true,
+        },
+      ])
+      .rpc();
+
+    const dataAccount = await program.account.data.fetch(data.publicKey);
+    assert.strictEqual(
+      dataAccount.someone.toString(),
+      payer.publicKey.toString()
+    );
+
+    // Another account
+    const another = anchor.web3.Keypair.generate();
+    await program.methods
+      .testInitAnother()
+      .accounts({ another: another.publicKey })
+      .signers([another])
+      .rpc();
+
+    try {
+      await program.methods
+        .testRemainingAccounts()
+        .accounts({
+          tokenProgram: TOKEN_PROGRAM_ID,
+        })
+        .remainingAccounts([
+          { pubkey: ata, isSigner: false, isWritable: false },
+          {
+            pubkey: another.publicKey,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .rpc();
+      assert.isTrue(false);
+    } catch (_err) {
+      assert.isTrue(_err instanceof anchor.AnchorError);
+      const err: anchor.AnchorError = _err;
+      assert.strictEqual(err.error.errorCode.number, 3002);
+      assert.strictEqual(
+        err.error.errorCode.code,
+        "AccountDiscriminatorMismatch"
+      );
+    }
+  });
+});