如何通过 javascript 结构中的 public 键来锚定 rpc 方法

How to pass public key in javascript struct to anchor rpc method

我正在尝试将 public 密钥传递给锚点 rpc 方法,但认为我没有在 Javascript 中正确生成它,我尝试用引号和不引号填充它,但无济于事。 锚点测试给了我一个 TypeError: key.toBuffer is not a function IF I pad it。 如果我不填充它,那么我会收到错误错误:由帐户引起的 AnchorError:my_account。错误代码:AccountDidNotSerialize。错误号:3004。错误消息:序列化帐户失败。

我怀疑问题出在我的 javascript 代码上:

  const pubkey1 = anchor.web3.Keypair.generate();
  const signatory1 =
    {
      name: "matt",
      publicKey: pubkey1.publicKey, // Error Code: AccountDidNotSerialize. Error Number: 3004
      // publicKey: '"' + pubkey1.publicKey + '"', // TypeError: key.toBuffer is not a function
    };
    // Invoke the update rpc.
    await program.rpc.addSignatory(signatory1, {
      accounts: {
        myAccount: myAccount.publicKey,
      },
    });

完整代码如下。

Lib.rs

use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod basic_1 {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        let my_account = &mut ctx.accounts.my_account;
        my_account.data = data;
        Ok(())
    }

    pub fn update(ctx: Context<Update>, data: u64) -> Result<()> {
        let my_account = &mut ctx.accounts.my_account;
        my_account.data = data;
        Ok(())
    }

    pub fn add_signatory(ctx: Context<Update>, signatory: Signatory) -> Result<()> {
        let my_account = &mut ctx.accounts.my_account;
        //my_account.data = data;
        my_account.signatories.push(signatory);
        Ok(())
    }

    pub fn add_signatories(ctx: Context<Update>, signatories: Vec<Signatory>) -> Result<()> {
        let my_account = &mut ctx.accounts.my_account;
        //my_account.data = data;
        my_account.signatories = signatories;
        Ok(())
    }


}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 100)]
    pub my_account: Account<'info, MyAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Update<'info> {
    #[account(mut)]
    pub my_account: Account<'info, MyAccount>,
}

#[account]
pub struct MyAccount {
    pub data: u64,
    pub project_id: u64,
    pub project_name: String,
    pub signatories: Vec<Signatory>,
    //pub signatories: [Signatory; 3]
}

#[derive(Default, AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Signatory {
    pub name: String,
    pub public_key: Pubkey,
}

基本-1.js

const assert = require("assert");
const anchor = require("@project-serum/anchor");
const { SystemProgram } = anchor.web3;

describe("basic-1", () => {
  // Use a local provider.
  const provider = anchor.AnchorProvider.local();

  // Configure the client to use the local cluster.
  anchor.setProvider(provider);

  it("Creates and initializes an account in a single atomic transaction (simplified)", async () => {
    // #region code-simplified
    // The program to execute.
    const program = anchor.workspace.Basic1;

    // The Account to create.
    const myAccount = anchor.web3.Keypair.generate();

    // Create the new account and initialize it with the program.
    // #region code-simplified
    await program.rpc.initialize(new anchor.BN(1234), {
      accounts: {
        myAccount: myAccount.publicKey,
        user: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
      },
      signers: [myAccount],
    });
    // #endregion code-simplified

    // Fetch the newly created account from the cluster.
    const account = await program.account.myAccount.fetch(myAccount.publicKey);

    // Check it's state was initialized.
    assert.ok(account.data.eq(new anchor.BN(1234)));

    // Store the account for the next test.
    _myAccount = myAccount;
  });

  it("Updates a previously created account", async () => {
    const myAccount = _myAccount;

    // #region update-test

    // The program to execute.
    const program = anchor.workspace.Basic1;

    // Invoke the update rpc.
    await program.rpc.update(new anchor.BN(4321), {
      accounts: {
        myAccount: myAccount.publicKey,
      },
    });

    // Fetch the newly updated account.
    const account = await program.account.myAccount.fetch(myAccount.publicKey);

    // Check it's state was mutated.
    assert.ok(account.data.eq(new anchor.BN(4321)));

    // #endregion update-test
  });

  it("add a single signatory", async () => {
    const myAccount = _myAccount;

    // #region update-test

    // The program to execute.
    const program = anchor.workspace.Basic1;
    const pubkey1 = anchor.web3.Keypair.generate();
    const pubkey2 = anchor.web3.Keypair.generate();
    // const pubkey1 = "abc";
    // const pubkey2 = "def";
    // console.log("deepak " + pubkey1.publicKey);
    console.log("deepak without prop" + pubkey1);
    const signatory1 =
    {
      name: "matt",
      publicKey: pubkey1.publicKey,
      // publicKey: '"' + pubkey1.publicKey + '"',
      // public_key: pubkey1.publicKey,
    };

    // Invoke the update rpc.
    await program.rpc.addSignatory(signatory1, {
      accounts: {
        myAccount: myAccount.publicKey,
      },
    });

    // Fetch the newly updated account.
    const account = await program.account.myAccount.fetch(myAccount.publicKey);
    //assert.ok(account.signatories.len().eq(new anchor.BN(1)));
    assert.equal(account.signatories.length, 1);


    const signatory2 =
    {
      name: "smith",
      publicKey: pubkey2.publicKey,
      // publicKey: '"' + pubkey2.publicKey + '"',
      // public_key: pubkey2.publicKey,
    };

    // Invoke the update rpc.
    await program.rpc.addSignatory(signatory2, {
      accounts: {
        myAccount: myAccount.publicKey,
      },
    });

    // Fetch the newly updated account.
    const account2 = await program.account.myAccount.fetch(myAccount.publicKey);
    //assert.ok(account.signatories.len().eq(new anchor.BN(1)));
    assert.equal(account2.signatories.length, 2);



    // Check it's state was mutated.
    assert.ok(account.data.eq(new anchor.BN(4321)));

    // #endregion update-test
  });

  /*
  it("add multiple signatories", async () => {
    const myAccount = _myAccount;

    // #region update-test

    // The program to execute.
    const program = anchor.workspace.Basic1;
    const pubkey1 = anchor.web3.Keypair.generate();
    const pubkey2 = anchor.web3.Keypair.generate();

    const signatories1 = [
      {
        name: "matt",
        public_key: pubkey1,
      },
      {
        name: "smith",
        public_key: pubkey2,
      },
    ];


    // Invoke the update rpc.
    await program.rpc.addSignatories(signatories1, {
      accounts: {
        myAccount: myAccount.publicKey,
      },
    });

    // Fetch the newly updated account.
    const account = await program.account.myAccount.fetch(myAccount.publicKey);

    // Check it's state was mutated.
    assert.ok(account.data.eq(new anchor.BN(4321)));

    // #endregion update-test
  });
*/

});

basic_1.json

{
  "version": "0.1.0",
  "name": "basic_1",
  "instructions": [
    {
      "name": "initialize",
      "accounts": [
        {
          "name": "myAccount",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "user",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "systemProgram",
          "isMut": false,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "data",
          "type": "u64"
        }
      ]
    },
    {
      "name": "update",
      "accounts": [
        {
          "name": "myAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "data",
          "type": "u64"
        }
      ]
    },
    {
      "name": "addSignatory",
      "accounts": [
        {
          "name": "myAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "signatory",
          "type": {
            "defined": "Signatory"
          }
        }
      ]
    },
    {
      "name": "addSignatories",
      "accounts": [
        {
          "name": "myAccount",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "signatories",
          "type": {
            "vec": {
              "defined": "Signatory"
            }
          }
        }
      ]
    }
  ],
  "accounts": [
    {
      "name": "MyAccount",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "data",
            "type": "u64"
          },
          {
            "name": "projectId",
            "type": "u64"
          },
          {
            "name": "projectName",
            "type": "string"
          },
          {
            "name": "signatories",
            "type": {
              "vec": {
                "defined": "Signatory"
              }
            }
          }
        ]
      }
    }
  ],
  "types": [
    {
      "name": "Signatory",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "name",
            "type": "string"
          },
          {
            "name": "publicKey",
            "type": "publicKey"
          }
        ]
      }
    }
  ],
  "metadata": {
    "address": "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
  }
}

你误解了问题。这里的问题不在于公钥传递。

添加签字人时,您已 运行 名 space 名。

您需要做的是预先计算存储 vec 中允许存储的最大签名数所需的 space。它必须有界限。

请参考https://borsh.io/#pills-specification来计算您需要多少space。

要验证这一点,您可以将 space 从 100 更改为 1000

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 1000)]
    pub my_account: Account<'info, MyAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

这对我来说很好

✔ Creates and initializes an account in a single atomic transaction (simplified) (186ms)
✔ Updates a previously created account (407ms)
✔ add a single signatory (409ms)
✔ add multiple signatories (414ms)