Solana Anchorのチュートリアル「A Minimal Example」のハマリポイント

SolanaでEthereumのOpenZeppelinやTruffleっぽく利用できる Anchor - A Minimal Example のハマリポイント。

原因究明まではやっていないため、以下すべて仮説。今回は対応策で解決はできたものの、状況によって異なる可能性あり。

found no record of a prior creditエラー

現象

「ANCHOR_WALLET= node client.js」を実行したときに出るエラー。

# ANCHOR_WALLET=/root/.config/solana/id.json node client.js
Running client.
Transaction simulation failed: Attempt to debit an account but found no record of a prior credit.

Translating error SendTransactionError: failed to send transaction: Transaction simulation failed: Attempt to debit an account but found no record of a prior credit.
    at Connection.sendEncodedTransaction (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:6591:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Connection.sendRawTransaction (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:6550:20)
    at async sendAndConfirmRawTransaction (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:8513:21)
    at async Provider.send (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/provider.js:85:22)
    at async Object.rpc [as initialize] (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:11:31)
    at async main (/usr/src/app/anchor-master/examples/tutorial/basic-0/client.js:22:3) {
  logs: []
}
node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

SendTransactionError: failed to send transaction: Transaction simulation failed: Attempt to debit an account but found no record of a prior credit.
    at Connection.sendEncodedTransaction (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:6591:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Connection.sendRawTransaction (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:6550:20)
    at async sendAndConfirmRawTransaction (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:8513:21)
    at async Provider.send (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/provider.js:85:22)
    at async Object.rpc [as initialize] (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:11:31)
    at async main (/usr/src/app/anchor-master/examples/tutorial/basic-0/client.js:22:3) {
  logs: []
}

原因

取引履歴が存在していない。つまり、チュートリアルのプログラムのdeployがちゃんとできていない。

対応

1.Solanaノードを起動しておく。

# solana-test-validator
--faucet-sol argument ignored, ledger already exists
Ledger location: test-ledger
Log: test-ledger/validator.log
Identity: 96aeBVR8ZopwXx3ttLiQWxjaVuWFfBhsmhocP1nj6ttK
Genesis Hash: 3rrq1z2jgqA74vVKJLseFiQvmhG7aF2zdP1iWayYsXiZ
Version: 1.8.0
Shred Version: 48177
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899

2.Solanaの設定をlocalhostにする

# solana config get
Config File: /root/.config/solana/cli/config.yml
RPC URL: https://api.mainnet-beta.solana.com
WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed)
Keypair Path: /root/.config/solana/id.json
Commitment: confirmed

# solana config set --url localhost
Config File: /root/.config/solana/cli/config.yml
RPC URL: http://localhost:8899
WebSocket URL: ws://localhost:8900/ (computed)
Keypair Path: /root/.config/solana/id.json
Commitment: confirmed

3.10 SOL airdropする
localhost, devnet, testnet, mainnetと、いろんなサーバーがあるが、トランザクションがなにかしら走る場合は、SOLの手数料が必要。

# solana airdrop 10
Requesting airdrop of 10 SOL

Signature: 53QEKUxsrjueDUP1XUmGxuK6ULDX9vNdNxRNRteiMw1ZyhqipLHvYN2rsn6BUHQkj1RyBTahp4WXiNJBH6mFLZJF

10 SOL

4.プログラムをデプロイする

# anchor deploy
Deploying workspace: http://localhost:8899
Upgrade authority: /root/.config/solana/id.json
Deploying program "basic-0"...
Program path: /usr/src/app/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so...
Program Id: 8Cj6ZYCXk6F15TgJqPr9pSjtMFaY4wmhxVcQPghcGeDs

Deploy success

5.client.jsを起動する
Successになったら成功。

# ANCHOR_WALLET=/root/.config/solana/id.json node client.js
Running client.
Success

insufficient fundsエラー

現象

# anchor deploy
Deploying workspace: http://localhost:8899
Upgrade authority: /root/.config/solana/id.json
Deploying program "basic-0"...
Program path: /usr/src/app/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so...
=================================================================================
Recover the intermediate account's ephemeral keypair file with
`solana-keygen recover` and the following 12-word seed phrase:
=================================================================================
scatter music supreme arm someone swap indicate strong stairs good appear because
=================================================================================
To resume a deploy, pass the recovered keypair as
the [PROGRAM_ADDRESS_SIGNER] argument to `solana deploy` or
as the [BUFFER_SIGNER] to `solana program deploy` or `solana write-buffer'.
Or to recover the account's lamports, pass it as the
[BUFFER_ACCOUNT_ADDRESS] argument to `solana program close`.
=================================================================================
Error: Account 3H3yDb6ph9fAT6iowbwizvR2CXCHJPoLBa9xsQtrGk5V has insufficient funds for spend (1.05455832 SOL) + fee (0.00077 SOL)
There was a problem deploying: Output { status: ExitStatus(ExitStatus(256)), stdout: "", stderr: "" }.

原因

手数料が足りない場合に発生するエラー。

対応

残高を増やす必要がある。
足りないと言われたアドレスは、上記の場合は「3H3yDb6ph9fAT6iowbwizvR2CXCHJPoLBa9xsQtrGk5V」になるため、まずクラスターのURLと残高を確認する。

% solana config get
Config File: /Users/user/.config/solana/cli/config.yml
RPC URL: https://api.devnet.solana.com
WebSocket URL: wss://api.devnet.solana.com/ (computed)
Keypair Path: /Users/user/.config/solana/id.json
Commitment: confirmed

% solana balance 3H3yDb6ph9fAT6iowbwizvR2CXCHJPoLBa9xsQtrGk5V
0 SOL

次にairdropで増やす。

% sol airdrop 1 3H3yDb6ph9fAT6iowbwizvR2CXCHJPoLBa9xsQtrGk5V
Requesting airdrop of 1 SOL

Signature: 4qGSUG25iDkxcW1c6kGLfHnvbLfWgyQX9bGqp4vJYDv5pbXmm9Qp85wV7FzAi6JAmUfemUDZc3DMKeN31q534PX7

1 SOL

クラスターURLによってairdrop上限が決まっているため(localnetは無限?、devnetだと2 SOLなど)、要注意。

補足

  1. Webサイト上でairdrop提供しているツールもあり、「solana testnet faucet」で検索するとHITする。そこで自分のアドレスを入れるとairdropできる。
  2. 「Balance unchanged」が表示された場合は、airdrop失敗。localnetの場合は「% solana logs」でログ確認を、devnetなどの場合は Solana Explorer でログ確認を。
    Solana Explorerだと以下のように表示される。以下の例ではairdrop量が多い(リクエスト5 SOLに対して、airdrop上限2 SOL)と言われている。
> Program log: Memo (len 39): "request too large; req: ◎5, cap: ◎2"

FetchError: request to http://localhost:8899/エラー

現象

# ANCHOR_WALLET=/root/.config/solana/id.json node client.js
Running client.
Translating error Error: failed to get recent blockhash: FetchError: request to http://localhost:8899/ failed, reason: connect ECONNREFUSED 127.0.0.1:8899
    at Connection.getRecentBlockhash (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:5965:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Provider.send (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/provider.js:77:31)
    at async Object.rpc [as initialize] (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:11:31)
    at async main (/usr/src/app/anchor-master/examples/tutorial/basic-0/client.js:22:3)
node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

Error: failed to get recent blockhash: FetchError: request to http://localhost:8899/ failed, reason: connect ECONNREFUSED 127.0.0.1:8899
    at Connection.getRecentBlockhash (/usr/src/app/anchor-master/examples/tutorial/node_modules/@solana/web3.js/lib/index.cjs.js:5965:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Provider.send (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/provider.js:77:31)
    at async Object.rpc [as initialize] (/usr/src/app/anchor-master/examples/tutorial/node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:11:31)
    at async main (/usr/src/app/anchor-master/examples/tutorial/basic-0/client.js:22:3)

Node.js v17.1.0

原因

localhostのSolanaノード(solana-test-validator)が起動していない。

対応

localhostのSolanaノードを起動する。

# solana-test-validator

node: --dns-result-order= is not allowedエラー

現象

【テスト結果が出ない状態(AsIs)】
一見、成功しているように見えるが、テストが走っていない。passingやdescribeが出力されておらず、テスト結果がfailになるように修正してもfailにならない(反映されない)。

$ anchor test
BPF SDK: /Users/user/.local/share/solana/install/releases/1.8.0/solana-release/bin/sdk/bpf
Running: rustup toolchain list -v
Running: cargo +bpf build --target bpfel-unknown-unknown --release
    Finished release [optimized] target(s) in 0.48s
Running: /Users/user/.local/share/solana/install/releases/1.8.0/solana-release/bin/sdk/bpf/dependencies/bpf-tools/llvm/bin/llvm-readelf --dyn-symbols /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so

To deploy this program:
  $ solana program deploy /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so
The program address will default to this keypair (override with --program-id):
  /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0-keypair.json
node: --dns-result-order= is not allowed in NODE_OPTIONS

【テスト結果が出る状態(本来期待する結果ToBe)】

# anchor test
BPF SDK: /root/.local/share/solana/install/releases/1.8.0/solana-release/bin/sdk/bpf
Running: rustup toolchain list -v
Running: cargo +bpf build --target bpfel-unknown-unknown --release
    Finished release [optimized] target(s) in 1.69s
Running: /root/.local/share/solana/install/releases/1.8.0/solana-release/bin/sdk/bpf/dependencies/bpf-tools/llvm/bin/llvm-readelf --dyn-symbols /usr/src/app/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so

To deploy this program:
  $ solana program deploy /usr/src/app/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so
The program address will default to this keypair (override with --program-id):
  /usr/src/app/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0-keypair.json
yarn run v1.22.17
$ /usr/src/app/anchor-master/examples/tutorial/node_modules/.bin/mocha -t 1000000 tests/


  basic-0
    ✔ Uses the workspace to invoke the initialize instruction (2758ms)


  1 passing (3s)

Done in 8.28s.

原因

anchorのバグ。Issues w/ anchor test #945
1.0.18.2で修正済み。

対応

Anchor CLIを最新にする。
インストールされているバージョンを調べる。自分の場合は0.18.0だった。

$ anchor --version
anchor-cli 0.18.0

Anchor公式サイトの Build from source for other operating systems に沿ってインストールする。

$ cargo install --git https://github.com/project-serum/anchor --tag v0.18.2 anchor-cli --locked

・・・

$ anchor --version
anchor-cli 0.18.2

ReferenceError: z is not definedエラー

現象

$ anchor test
BPF SDK: /Users/user/.local/share/solana/install/releases/1.8.0/solana-release/bin/sdk/bpf
Running: rustup toolchain list -v
Running: cargo +bpf build --target bpfel-unknown-unknown --release
    Finished release [optimized] target(s) in 0.47s
Running: /Users/user/.local/share/solana/install/releases/1.8.0/solana-release/bin/sdk/bpf/dependencies/bpf-tools/llvm/bin/llvm-readelf --dyn-symbols /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so

To deploy this program:
  $ solana program deploy /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0.so
The program address will default to this keypair (override with --program-id):
  /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/target/deploy/basic_0-keypair.json
yarn run v1.22.17
$ /Users/user/Desktop/blockchain/anchor-master/examples/tutorial/node_modules/.bin/mocha -t 1000000 tests/

ReferenceError: z is not defined
    at Object.<anonymous> (/Users/user/Desktop/blockchain/anchor-master/examples/tutorial/basic-0/tests/basic-0.js:17:1)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at ModuleWrap.<anonymous> (internal/modules/esm/translators.js:195:29)
    at ModuleJob.run (internal/modules/esm/module_job.js:145:37)
    at async Loader.import (internal/modules/esm/loader.js:182:24)
    at async formattedImport (/Users/user/Desktop/blockchain/anchor-master/examples/tutorial/node_modules/mocha/lib/nodejs/esm-utils.js:7:14)
    at async Object.exports.requireOrImport (/Users/user/Desktop/blockchain/anchor-master/examples/tutorial/node_modules/mocha/lib/nodejs/esm-utils.js:48:32)
    at async Object.exports.loadFilesAsync (/Users/user/Desktop/blockchain/anchor-master/examples/tutorial/node_modules/mocha/lib/nodejs/esm-utils.js:88:20)
    at async singleRun (/Users/user/Desktop/blockchain/anchor-master/examples/tutorial/node_modules/mocha/lib/cli/run-helpers.js:125:3)
    at async Object.exports.handler (/Users/user/Desktop/blockchain/anchor-master/examples/tutorial/node_modules/mocha/lib/cli/run.js:374:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

原因

原因はわからなかったが、いじりまくっているうちにおかしくなってしまったと思われる。

対応

きれいな状態で1からやり直す。自分の場合は以下2点で直った。

  1. 以下をもとに環境を最新版にする。Yarnも最新版にする。
    Installing Dependencies
  2. Anchorの最新版をGitHubから改めてDLしてから、再度チュートリアルを実行する。
    GitHub - project-serum/anchor

ログがどこにあるかわからない

deployログは .anchor > program-logs にアドレス毎に出力される。

anchor version is not correctエラー

現象

anchorを バージョンアップ してから実行すると、バージョンが違うと言われる。

% cargo install --git https://github.com/project-serum/anchor --tag v0.19.0 anchor-cli --locked

% anchor --version
Only x86_64 / Linux distributed in NPM package right now.
Trying globally installed anchor.
Globally installed anchor version is not correct. Expected “anchor-cli 0.17.0”, found “anchor-cli 0.19.0".

原因

npmとcargoで重複インストールされていて、npmの古いバージョンが呼ばれてしまっていた。

対応

npmのanchorを削除する。

% npm list -g
/Users/sxdev/.nodebrew/node/v16.11.1/lib
├── @project-serum/anchor-cli@0.17.0
├── corepack@0.9.0
├── ganache-cli@6.12.2
├── mocha@9.1.2
├── npm@8.0.0
├── truffle@5.4.19
└── yarn@1.22.15

% npm uninstall -g @project-serum/anchor-cli

% anchor --version
anchor-cli 0.19.0

Attempt to load a program that does not existエラー

現象

anchor testするとプログラムが存在しないと言われて、ローカルバリデータにデプロイできない。
(このケースでは、solana-test-validatorでローカルバリデータを起動しつつ、anchor testを実施した)

% anchor test --skip-local-validator

Deploy success
yarn run v1.22.10
$ /Users/user/Documents/Programming/Blockchain/solana-anchor-react-minimal-example/anchor/tutorial/basic-3/node_modules/.bin/mocha -t 1000000 tests/


  basic-3
Transaction simulation failed: Attempt to load a program that does not exist

    1) Performs CPI from puppet master to puppet


  0 passing (76ms)
  1 failing

  1) basic-3
       Performs CPI from puppet master to puppet:
     Error: failed to send transaction: Transaction simulation failed: Attempt to load a program that does not exist
      at Connection.sendEncodedTransaction (node_modules/@solana/web3.js/lib/index.cjs.js:6591:13)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async Connection.sendRawTransaction (node_modules/@solana/web3.js/lib/index.cjs.js:6550:20)
      at async sendAndConfirmRawTransaction (node_modules/@solana/web3.js/lib/index.cjs.js:8513:21)
      at async Provider.send (node_modules/@project-serum/anchor/dist/cjs/provider.js:90:22)
      at async Object.rpc [as initialize] (node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:31:31)
      at async Context.<anonymous> (tests/basic-3.js:17:16)



error Command failed with exit code 1.

なお、「anchor test」だと通る。

原因

declare_idが間違っているため、プログラムが発見できない状態になっている。
idlの各ファイルにdeclare_idが書き込まれ、その情報をもとに、programs(lib.rs)を探す仕組みになっている。

対応

以下コマンドでPublic Keyを取得して、Anchor.tomlとlib.rsに、正しいdeclare_idに書き換える。

% solana address -k target/deploy/[対象のKeypair]

念のため最後にdeployしておく。

% anchor deploy

「custom program error: 0x1004」エラー

現象

以下のように「custom program error: 0x1004」エラーが表示される。

% anchor test
〜〜〜省略〜〜〜
Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x1004
〜〜〜省略〜〜〜

原因

Anchorのdeclare_idが誤っているため。

対応

Attempt to load a program that does not existエラー の「対応」を参照。