見出し画像

トランザクションエラーの診断方法

サポートネットワークへのエラー共有について

エラーの内容が理解できず、他者に相談したい場合、状況を説明することが難しい場合があります。これは特に、Metaplex Umi、Solana SDK、Solana Web3jsなどのSDKを使用してトランザクションを送信する際によく発生します。

これらのクライアントは通常、トランザクションが成功するかどうかを確認するため、RPCに対してsimulation/pre-flightを送信します。トランザクションが失敗すると判断された場合、チェーンには送信されず、単にエラーメッセージが表示されるだけとなります。

これはネットワークとして適切な動作ですが、他者からサポートを受けるための情報が得られません。このような場合、pre-flight transaction(シミュレーション)をスキップし、失敗するトランザクションを強制的にチェーンに記録させることで、他者と共有可能な情報を得ることができます。

Preflightのスキップについて

トランザクションの送信に使用するほとんどのSDKには、トランザクション送信時に`skipPreflight`を使用できる機能が備わっています。これにより、simulationとpreflightをスキップし、チェーンに強制的にトランザクションを記録させることができます。

この方法が有用な理由は、送信しようとした正確なトランザクションが以下の情報を含めてチェーンに記録・保存されるからです。

  • 使用されたすべてのアカウント

  • 送信されたすべてのinstruction

  • エラーメッセージを含むすべてのログ

この失敗したトランザクションを他者に送ることで、トランザクションの詳細を確認し、失敗の原因を診断することができます。

この機能はMainnetDevnetの両方で動作します。Localnetでも動作しますが、より複雑で詳細の共有が困難です。

umiについて

`skipPreflight` は Metaplex Umi の `sendAndConfirm()` および `send()` 関数の引数で確認でき、以下のように有効化することができます。

sendAndConfirm()

const tx = createV1(umi, {
    ...args
}).sendAndConfirm(umi, {send: { skipPreflight: true}})

// Convert signature to string
const signature = base58.deserialize(tx.signature);

// Log transaction signature
console.log(signature)

send()

const tx = createV1(umi, {
    ...args
}).send(umi, {skipPreflight: true})

// Convert signature to string
const signature = base58.deserialize(tx);

// Log transaction signature
console.log(signature)

web3js

// Create Connection
const connection = new Connection("https://api.devnet.solana.com", "confirmed",);

// Create your transaction
const transaction = new VersionedTransaction()

// Add skipPreflight to the sendTransaction() function
const res = await connection.sendTransaction(transaction, [...signers], {skipPreflight: true})

// Log out the transaction signature
console.log(res)

solana-client (rust)

// Create Connection
let rpc_client = rpc_client::RpcClient::new("https://api.devnet.solana.com".to_string());

// Create your transaction
let transaction = new Transaction()

// Add skipPreflight to the sendTransaction() function
let res = rpc_client
    .send_transaction_with_config(&create_asset_tx, RpcSendTransactionConfig {
        skip_preflight: true,
        preflight_commitment: Some(CommitmentConfig::confirmed().commitment),
        encoding: None,
        max_retries: None,
        min_context_slot: None,
    })
    .await
    .unwrap();

// Log out the transaction signature
println!("Signature: {:?}", res)

トランザクションIDをログに出力することで、Solanaのブロックチェーンエクスプローラーにアクセスし、失敗したトランザクションを検索することができます。

  • SolanaFM

  • Solscan

  • Solana Explorer

このトランザクションIDまたはエクスプローラーのリンクを、サポートできる可能性のある人と共有することができます。

よく発生するエラー

以下のようなエラーがよく発生します。

エラーコード xx (23)

通常、エラーコードを説明する追加テキストが付随していますが、これらのコードが説明のない形で単独で表示されることがあります。このような場合、エラーを発生させたプログラムが分かっている場合は、GitHubでそのプログラムを見つけることができ、プログラムの全ての可能なエラーを列挙した errors.rs ページが存在することがあります。

インデックス0から始めて、リスト内のエラーの位置を数え下げる/計算することができます。
以下は、Metaplex CoreプログラムのError.rsページの例です。

https://github.com/metaplex-foundation/mpl-core/blob/main/programs/mpl-core/src/error.rs

失敗したトランザクションからエラーコード20を受け取った場合、以下のように解釈できます。

/// 20 - Missing update authority
    #[error("Missing update authority")]
    MissingUpdateAuthority,

6xxxエラーコード(6002)

6xxxエラーコードは、カスタムプログラムのAnchorエラーコードです。上記のように、GitHubでプログラムを見つけることができれば、通常、プログラムのエラーとコードを列挙したerrors.rsファイルが存在します。Anchorのカスタムプログラムエラーコードは6000から始まるため、リストの最初のエラーは6000、2番目は6001というように続きます。理論的には、エラーコードの末尾の数字だけを取り出し(例:6026の場合は26)、インデックス0から始めてエラーを確認することができます。

例として、Mpl Core Candy Machineプログラムを見てみましょう。これはAnchorプログラムなので、エラーコードは6xxxで始まります。

トランザクションが`6006`というエラーを返す場合、この数字の末尾である`6`を取り出し、インデックス0から始めてerror.rsリストを確認することができます。

#[msg("Candy machine is empty")]
CandyMachineEmpty,

Hexエラー

まれに、`0x1e`のような16進数(hex)形式でエラーが返されることがあります。
この場合、16進数から10進数への変換ツールを使用して、エラーを適切な形式に変換することができます。

  • エラーがxx形式の場合は、エラーコードxxを参照してください

  • エラーが6xxx形式の場合は、エラーコード6xxxを参照してください

アカウントの所有者が不正

このエラーは通常、アカウントリストに渡されたアカウントが想定されたプログラムによって所有されていないために発生し、失敗することを意味します。例えば、Token Metadataアカウントは、Token Metadata Programによって所有されていることが期待されます。トランザクションのアカウントリスト内の特定の位置にあるアカウントがこの条件を満たしていない場合、トランザクションは失敗します。

このタイプのエラーは、PDAが間違ったseedsで生成された場合や、アカウントがまだ初期化/作成されていない場合によく発生します。

アサートエラー

アサートエラーはマッチングエラーです。アサートは通常2つの変数(多くの場合はaddress/publicKey)を取り、それらが同じ期待値であることを確認します。一致しない場合、`Assert left='value' right='value'`エラーが発生し、2つの値が期待通りに一致しないことが詳細に示されます。

0x1 デビットの試行エラー

`Attempt to debit an account but found no record of a prior credit`というエラーは一般的なエラーです。このエラーは基本的に、アカウント内にSOLが全くないことを示しています。


いいなと思ったら応援しよう!