PDA(Program Derived Addresses) を試していた時に発生した現象。
Agenda
(補足)ポイント
以下2点が本現象のポイント
- 「% anchor test」を実施したときは正常に動作するが、「% anchor test --skip-local-validator」でlocalnetにデプロイすると本現象が発生する。
- キーペアの生成(anchor.web3.Keypair.generate())をして利用した場合は正常に動作するが、自分のKey(anchor.AnchorProvider.local().wallet.publicKey)を使うと本現象が発生する。
現象
solana-test-validatorを起動して、以下を実行すると「custom program error: 0x0」エラーが発生。
% anchor test --skip-local-validator
0 passing (325ms)
1 failing
1) hello
Creates a User Stats:
Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x0
at Connection.sendEncodedTransaction (node_modules/@solana/web3.js/src/connection.ts:4506:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Connection.sendRawTransaction (node_modules/@solana/web3.js/src/connection.ts:4465:20)
at sendAndConfirmRawTransaction (node_modules/@project-serum/anchor/src/provider.ts:288:21)
at AnchorProvider.sendAndConfirm (node_modules/@project-serum/anchor/src/provider.ts:148:14)
at MethodsBuilder.rpc [as _rpcFn] (node_modules/@project-serum/anchor/src/program/namespace/rpc.ts:29:16)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
* Terminal will be reused by tasks, press any key to close it.
原因
「custom program error: 0x0」は、すでにアカウントが作成されている、という意味らしい。つまり、すでにPDAアカウントがすでに作成されているため、本エラーが発生している。
「% anchor test --skip-local-validator」を利用していたため、最初にPDAアカウント作成して、それがずっと残っていた。
補足
以下の原因は、anchor testをすると、毎回リセットされた状態になるためエラーが発生しなかった。
- 「% anchor test」を実施したときは正常に動作するが、「% anchor test --skip-local-validator」でlocalnetにデプロイすると本現象が発生する。
以下の原因は、キーペアを新規作成していたため、PDAアカウントが作成されていなかったため、エラーが発生しなかった。
- キーペアの生成(anchor.web3.Keypair.generate())をして利用した場合は正常に動作するが、自分のKey(anchor.AnchorProvider.local().wallet.publicKey)を使うと本現象が発生する。
対応
PDAアカウントが作成されているか確認する
PDAアカウントをfetchして、本当に作成されているのか確認する。
const [userStatsPDA, _] = await PublicKey.findProgramAddress(
[
anchor.utils.bytes.utf8.encode('user-stats'),
provider.wallet.publicKey.toBuffer(),
// user.publicKey.toBuffer(),
],
program.programId
);
let fetchUserStats = await program.account.userStats.fetch(userStatsPDA);
console.log(fetchUserStats);
test-ledgerを削除する
test-ledgerフォルダにデータが入っているため、一旦削除してから、「% anchor test --skip-local-validator」を実行する。
1回目の実行は成功して(PDAアカウントが正常に作成されている)、2回目を実行すると0x0エラーになるはず(すでにPDAアカウントが作成されていて、そのデータがtest-ledgerフォルダに入っているため)。