将复杂类型传递给锚点 rpc 失败
Passing complex types to anchor rpc fails
我修改了基本教程示例以传递结构,但是当我 运行“锚点测试”时它失败并显示 TypeError: Blob.encode[data] requires (length 4) Buffer as src
当我搜索这个错误时,我在互联网上找不到任何东西。
附上代码。如果我以某种方式弄错了,请告诉我。
谢谢,
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: Vec<u8>,
pub signatories: Vec<Signatory>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Signatory {
pub name: Vec<u8>,
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 signatory1 =
{
name: "matt",
public_key: pubkey1,
};
// 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);
// 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
});
});
锚点测试输出
abcd@abcd:~/code/anchor/examples/tutorial/basic-1$ anchor test
BPF SDK: /home/abcd/.local/share/solana/install/releases/1.10.8/solana-release/bin/sdk/bpf
cargo-build-bpf child: rustup toolchain list -v
cargo-build-bpf child: cargo +bpf build --target bpfel-unknown-unknown --release
Finished release [optimized] target(s) in 0.17s
cargo-build-bpf child: /home/abcd/.local/share/solana/install/releases/1.10.8/solana-release/bin/sdk/bpf/dependencies/bpf-tools/llvm/bin/llvm-readelf --dyn-symbols /home/abcd/code/anchor/examples/tutorial/basic-1/target/deploy/basic_1.so
To deploy this program:
$ solana program deploy /home/abcd/code/anchor/examples/tutorial/basic-1/target/deploy/basic_1.so
The program address will default to this keypair (override with --program-id):
/home/abcd/code/anchor/examples/tutorial/basic-1/target/deploy/basic_1-keypair.json
Found a 'test' script in the Anchor.toml. Running it as a test suite!
Running test suite: "/home/abcd/code/anchor/examples/tutorial/basic-1/Anchor.toml"
yarn run v1.22.18
$ /home/abcd/code/anchor/examples/tutorial/node_modules/.bin/mocha -t 1000000 tests/
basic-1
✔ Creates and initializes an account in a single atomic transaction (simplified) (250ms)
✔ Updates a previously created account (411ms)
1) add a single signatory
2) add multiple signatories
2 passing (698ms)
2 failing
1) basic-1
add a single signatory:
TypeError: Blob.encode[data] requires (length 4) Buffer as src
at Blob.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:2321:13)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at WrappedLayout.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/@project-serum/borsh/dist/lib/index.js:67:28)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at BorshInstructionCoder._encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:91:28)
at BorshInstructionCoder.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:76:21)
at /home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/index.js:41:100
at ix (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/instruction.js:50:23)
at txFn (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/transaction.js:16:20)
at Object.rpc [as addSignatory] (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:9:24)
at Context.<anonymous> (tests/basic-1.js:82:23)
at processImmediate (node:internal/timers:466:21)
2) basic-1
add multiple signatories:
TypeError: Blob.encode[data] requires (length 4) Buffer as src
at Blob.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:2321:13)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at WrappedLayout.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/@project-serum/borsh/dist/lib/index.js:67:28)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at /home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1113:25
at Array.reduce (<anonymous>)
at Sequence.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1112:22)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at WrappedLayout.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/@project-serum/borsh/dist/lib/index.js:67:28)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at BorshInstructionCoder._encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:91:28)
at BorshInstructionCoder.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:76:21)
at /home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/index.js:41:100
at ix (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/instruction.js:50:23)
at txFn (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/transaction.js:16:20)
at Object.rpc [as addSignatories] (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:9:24)
at Context.<anonymous> (tests/basic-1.js:120:23)
at processImmediate (node:internal/timers:466:21)
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
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": "bytes"
},
{
"name": "signatories",
"type": {
"vec": {
"defined": "Signatory"
}
}
}
]
}
}
],
"types": [
{
"name": "Signatory",
"type": {
"kind": "struct",
"fields": [
{
"name": "name",
"type": "bytes"
},
{
"name": "publicKey",
"type": "publicKey"
}
]
}
}
],
"metadata": {
"address": "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
}
}
更新 1
按照下面 Jon C 的建议将类型更改为字符串后 - 测试 运行s。
但是,如果我两次调用 addSignatory 方法,它会失败并显示错误“错误:由帐户引起的 AnchorError:my_account。错误代码:AccountDidNotSerialize。错误编号:3004。错误消息:无法序列化帐户。”。
已更新基础-1.js
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 signatory1 =
{
name: "matt",
public_key: pubkey1,
};
// 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",
public_key: pubkey2,
};
// 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
});
锚点测试输出
1) basic-1
add a single signatory:
Error: AnchorError caused by account: my_account. Error Code: AccountDidNotSerialize. Error Number: 3004. Error Message: Failed to serialize the account.
at Function.parse (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/error.js:138:20)
at translateError (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/error.js:224:37)
at Object.rpc [as addSignatory] (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:18:53)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Context.<anonymous> (tests/basic-1.js:101:5)
更新 2
所以我想出了更多的东西,感谢@JonC 的提示帮助我前进。
- 要调用 Rust 方法,您需要将方法名称更改为
javascript 中的 snakecase,因此 add_signatory 将从 JS 中调用为 addSignatory。
- 在作为参数传递给 rust 方法之前,您需要在 JS 中的字符串周围添加引号。所以需要保证在JS代码中字符串变量用'"'填充。
- 我仍然不确定为什么这不起作用,但是将 public 键作为字符串从 JS 发送到 Rust 会导致锚点测试失败并出现“帐户无法序列化”错误,如此处所述。仍在尝试解决这个问题。
您的签名者中的 name
字段在后端定义为 Vec<u8>
,但您从前端传递了一个字符串。尝试将 Signatory 类型更新为:
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Signatory {
pub name: String,
pub public_key: Pubkey,
}
这样,序列化程序就会知道将名称正确编码为字符串,而不是字节。
我修改了基本教程示例以传递结构,但是当我 运行“锚点测试”时它失败并显示 TypeError: Blob.encode[data] requires (length 4) Buffer as src 当我搜索这个错误时,我在互联网上找不到任何东西。
附上代码。如果我以某种方式弄错了,请告诉我。 谢谢,
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: Vec<u8>,
pub signatories: Vec<Signatory>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Signatory {
pub name: Vec<u8>,
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 signatory1 =
{
name: "matt",
public_key: pubkey1,
};
// 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);
// 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
});
});
锚点测试输出
abcd@abcd:~/code/anchor/examples/tutorial/basic-1$ anchor test
BPF SDK: /home/abcd/.local/share/solana/install/releases/1.10.8/solana-release/bin/sdk/bpf
cargo-build-bpf child: rustup toolchain list -v
cargo-build-bpf child: cargo +bpf build --target bpfel-unknown-unknown --release
Finished release [optimized] target(s) in 0.17s
cargo-build-bpf child: /home/abcd/.local/share/solana/install/releases/1.10.8/solana-release/bin/sdk/bpf/dependencies/bpf-tools/llvm/bin/llvm-readelf --dyn-symbols /home/abcd/code/anchor/examples/tutorial/basic-1/target/deploy/basic_1.so
To deploy this program:
$ solana program deploy /home/abcd/code/anchor/examples/tutorial/basic-1/target/deploy/basic_1.so
The program address will default to this keypair (override with --program-id):
/home/abcd/code/anchor/examples/tutorial/basic-1/target/deploy/basic_1-keypair.json
Found a 'test' script in the Anchor.toml. Running it as a test suite!
Running test suite: "/home/abcd/code/anchor/examples/tutorial/basic-1/Anchor.toml"
yarn run v1.22.18
$ /home/abcd/code/anchor/examples/tutorial/node_modules/.bin/mocha -t 1000000 tests/
basic-1
✔ Creates and initializes an account in a single atomic transaction (simplified) (250ms)
✔ Updates a previously created account (411ms)
1) add a single signatory
2) add multiple signatories
2 passing (698ms)
2 failing
1) basic-1
add a single signatory:
TypeError: Blob.encode[data] requires (length 4) Buffer as src
at Blob.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:2321:13)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at WrappedLayout.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/@project-serum/borsh/dist/lib/index.js:67:28)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at BorshInstructionCoder._encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:91:28)
at BorshInstructionCoder.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:76:21)
at /home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/index.js:41:100
at ix (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/instruction.js:50:23)
at txFn (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/transaction.js:16:20)
at Object.rpc [as addSignatory] (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:9:24)
at Context.<anonymous> (tests/basic-1.js:82:23)
at processImmediate (node:internal/timers:466:21)
2) basic-1
add multiple signatories:
TypeError: Blob.encode[data] requires (length 4) Buffer as src
at Blob.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:2321:13)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at WrappedLayout.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/@project-serum/borsh/dist/lib/index.js:67:28)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at /home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1113:25
at Array.reduce (<anonymous>)
at Sequence.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1112:22)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at WrappedLayout.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/@project-serum/borsh/dist/lib/index.js:67:28)
at Structure.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/node_modules/buffer-layout/lib/Layout.js:1263:26)
at BorshInstructionCoder._encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:91:28)
at BorshInstructionCoder.encode (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/coder/borsh/instruction.js:76:21)
at /home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/index.js:41:100
at ix (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/instruction.js:50:23)
at txFn (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/transaction.js:16:20)
at Object.rpc [as addSignatories] (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:9:24)
at Context.<anonymous> (tests/basic-1.js:120:23)
at processImmediate (node:internal/timers:466:21)
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
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": "bytes"
},
{
"name": "signatories",
"type": {
"vec": {
"defined": "Signatory"
}
}
}
]
}
}
],
"types": [
{
"name": "Signatory",
"type": {
"kind": "struct",
"fields": [
{
"name": "name",
"type": "bytes"
},
{
"name": "publicKey",
"type": "publicKey"
}
]
}
}
],
"metadata": {
"address": "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
}
}
更新 1
按照下面 Jon C 的建议将类型更改为字符串后 - 测试 运行s。 但是,如果我两次调用 addSignatory 方法,它会失败并显示错误“错误:由帐户引起的 AnchorError:my_account。错误代码:AccountDidNotSerialize。错误编号:3004。错误消息:无法序列化帐户。”。
已更新基础-1.js
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 signatory1 =
{
name: "matt",
public_key: pubkey1,
};
// 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",
public_key: pubkey2,
};
// 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
});
锚点测试输出
1) basic-1
add a single signatory:
Error: AnchorError caused by account: my_account. Error Code: AccountDidNotSerialize. Error Number: 3004. Error Message: Failed to serialize the account.
at Function.parse (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/error.js:138:20)
at translateError (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/error.js:224:37)
at Object.rpc [as addSignatory] (/home/abcd/code/anchor/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:18:53)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Context.<anonymous> (tests/basic-1.js:101:5)
更新 2
所以我想出了更多的东西,感谢@JonC 的提示帮助我前进。
- 要调用 Rust 方法,您需要将方法名称更改为 javascript 中的 snakecase,因此 add_signatory 将从 JS 中调用为 addSignatory。
- 在作为参数传递给 rust 方法之前,您需要在 JS 中的字符串周围添加引号。所以需要保证在JS代码中字符串变量用'"'填充。
- 我仍然不确定为什么这不起作用,但是将 public 键作为字符串从 JS 发送到 Rust 会导致锚点测试失败并出现“帐户无法序列化”错误,如此处所述。仍在尝试解决这个问题。
您的签名者中的 name
字段在后端定义为 Vec<u8>
,但您从前端传递了一个字符串。尝试将 Signatory 类型更新为:
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Signatory {
pub name: String,
pub public_key: Pubkey,
}
这样,序列化程序就会知道将名称正确编码为字符串,而不是字节。