如何通过 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)
我正在尝试将 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)