锚/索拉纳错误0xbc2(3010)—给定的帐户未签名



我在Golang中的锚交易,尽管在锚JS代码中工作良好,但不想玩得很好,并且给了我一个关于签名者帐户(在这种情况下称为authority)没有签名的错误消息,即使我确实签署了。

我的指令代码结构是这样的:


#[account]
#[derive(Default)]
pub struct Device {
pub ipv4: [u8; 4],
pub hostname: String,
bump: u8,
status: DeviceStatus,
local_key: Pubkey,
}
#[derive(Accounts)]
#[instruction(local_key: Pubkey)]
pub struct RegisterDevice<'info> {
#[account(init,
space = 128,
seeds = [local_key.as_ref()],
bump,
payer = authority,
)]
pub device: Box<Account<'info, Device>>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}

我的锚代码工作正常,看起来像这样:


it("registers a device", async () => {
const localKey = anchor.web3.Keypair.generate();
const [devicePDA, _devicePDABump] =
await anchor.web3.PublicKey.findProgramAddress(
[localKey.publicKey.toBuffer()],
program.programId
);
await program.methods
.registerDevice(localKey.publicKey)
.accounts({
device: devicePDA,
authority: provider.wallet.PublicKey,
systemProgram: SystemProgram.programId,
})
.rpc();
});

Go代码(使用solana-go库):

registerDeviceInst, err := worknet.NewRegisterDeviceInstruction(
devicePubkey,
pdaPubkey,
*walletPubKey,
gagliardetto.SystemProgramID,
).ValidateAndBuild()
if err != nil {
return err
}
blockHash, err := client.GetRecentBlockhash(context.TODO(), gagliardettorpc.CommitmentFinalized)
if err != nil {
return nil
}
txn, err := gagliardetto.NewTransaction([]gagliardetto.Instruction{registerDeviceInst}, blockHash.Value.Blockhash)
if err != nil {
return err
}
_, err = txn.Sign(func(key gagliardetto.PublicKey) *gagliardetto.PrivateKey {
return walletPrivKey
})
if err != nil {
return err
}

以下是TXN的转储和响应:

(*solana.Transaction)(0x14000110000)(   
├─ Signatures[len=1]
│    └─ v1f9bZhMuJkbsrB54y2w36TQdpZDG4bxgbpwrkuD5xSbtCT9kshRnymKB28b2peb5u8YKDoAPRNz4rVz8Vt3pAY
├─ Message
│    ├─ RecentBlockhash: 6PXLreSEHvqP22AsGcAqFzt5Wv1oMGXH8WfUwVuDUtXH
│    ├─ AccountKeys[len=4]
│    │    ├─ HEwe5nVn4y2gV4tCQ3hZ6a3QxB9a72NyXstWxBk4q5ct
│    │    ├─ HqhAGJwjHo36AJwfPzaWAu224rVF9bDWnN9tx6JSdjot
│    │    ├─ 11111111111111111111111111111111
│    │    └─ EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
│    └─ Header
│       ├─ NumRequiredSignatures: 1
│       ├─ NumReadonlySignedAccounts: 0
│       └─ NumReadonlyUnsignedAccounts: 2
└─ Instructions[len=1]
└─ Program: Worknet EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
└─ Instruction: RegisterDevice
├─ Params[len=1]
│    └─ LocalKey: (solana.PublicKey) (len=32 cap=32) 8kb1Y6pkENNHnjzkeqWobdjnKTxiHD7fkjAEks2oEoyD
└─ Accounts[len=3]
├─        device: HqhAGJwjHo36AJwfPzaWAu224rVF9bDWnN9tx6JSdjot [WRITE] 
├─     authority: HEwe5nVn4y2gV4tCQ3hZ6a3QxB9a72NyXstWxBk4q5ct [WRITE, SIGN] 
└─ systemProgram: 11111111111111111111111111111111 [] 
)
daoctl: error: (*jsonrpc.RPCError)(0x1400038d1a0)({
Code: (int) -32002,
Message: (string) (len=90) "Transaction simulation failed: Error processing Instruction 0: custom program error: 0xbc2",
Data: (map[string]interface {}) (len=3) {
(string) (len=8) "accounts": (interface {}) <nil>,
(string) (len=3) "err": (map[string]interface {}) (len=1) {
(string) (len=16) "InstructionError": ([]interface {}) (len=2 cap=2) {
(json.Number) (len=1) "0",
(map[string]interface {}) (len=1) {
(string) (len=6) "Custom": (json.Number) (len=4) "3010"
}
}
},
(string) (len=4) "logs": ([]interface {}) (len=5 cap=8) {
(string) (len=63) "Program EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9 invoke [1]",
(string) (len=40) "Program log: Instruction: RegisterDevice",
(string) (len=151) "Program log: AnchorError caused by account: authority. Error Code: AccountNotSigner. Error Number: 3010. Error Message: The given account did not sign.",
(string) (len=90) "Program EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9 consumed 4085 of 200000 compute units",
(string) (len=88) "Program EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9 failed: custom program error: 0xbc2"
}
}
})

锚JS做什么魔法,我在我的Go客户端代码缺失?

好的,我已经成功地找出了问题所在。

阅读https://docs.solana.com/developing/programming-model/transactions,我注意到它提到:

Solana runtime…验证每个签名都是由与同一索引上的公钥对应的私钥签名的。在消息的帐户地址数组中。

如果你看一下我在Go代码中传递的帐户,authority位于索引1,而不是像它的签名那样索引0:

└─ Accounts[len=3]
├─ device: HqhAGJwjHo36AJwfPzaWAu224rVF9bDWnN9tx6JSdjot [WRITE] 
├─ authority: HEwe5nVn4y2gV4tCQ3hZ6a3QxB9a72NyXstWxBk4q5ct [WRITE, SIGN] 
└─ systemProgram: 11111111111111111111111111111111 [] 

因此,解决方案是改变锚结构定义中帐户的顺序,重新生成Go绑定,并以正确的顺序传递帐户,以便authority帐户在事务中索引为0。

#[derive(Accounts)]
#[instruction(local_key: Pubkey)]
pub struct RegisterDevice<'info> {
+    #[account(mut)]
+    pub authority: Signer<'info>,
+
#[account(init,
space = 128,
seeds = [local_key.as_ref()],
bump,
payer = authority,
)]
pub device: Box<Account<'info, Device>>,

-    #[account(mut)]
-    pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}

现在交易符号正确。我认为导致锚代码工作的原因是它将在RPC调用中执行一些自动帐户解析,这将正确地放置授权/签名(?),尽管它在生成的Go代码中无序。

相关内容

  • 没有找到相关文章

最新更新