You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用带PDA的Solana Anchor电影评论程序时交易失败求助

问题:Devnet环境下Vue应用调用Anchor电影评论程序addMovieReview失败

本地克隆Unboxed-Software/anchor-movie-review-program测试正常,但在Vue应用中调用地址为CLA5Pk8tpcsA3RPmCYPaRNBdU6xBknRnqshsT1bKT7if的程序时,两种调用方式均交易失败。


方式一:使用Anchor Program客户端调用

代码实现

const wallet = useWallet();
const programId = new PublicKey("CLA5Pk8tpcsA3RPmCYPaRNBdU6xBknRnqshsT1bKT7if");
const provider = new anchor.AnchorProvider(
    connection,
    wallet,
    anchor.AnchorProvider.defaultOptions()
);
// Generate the program client from IDL. Where MyRaffle is the idl generated by program
const program = new anchor.Program(MyRaffle, programId, provider);
const movie = {
        title: "Just a test movie",
        description: "Wow what a good movie it was real great",
        rating: 5,
    };
const [moviePda] = anchor.web3.PublicKey.findProgramAddressSync(
        [Buffer.from(movie.title), wallet.publicKey.value.toBuffer()],
        program.programId
    );

const tx = await program.methods.addMovieReview(movie.title,  
                    movie.description, movie.rating ).accounts({
                    movieReview: moviePda,
                    initializer: wallet.publicKey.value,
                    systemProgram: anchor.web3.SystemProgram.programId,
                }).rpc();

对应IDL

{
    "version": "0.1.0",
    "name": "anchor_movie_review_program",
    "instructions": [
      {
        "name": "addMovieReview",
        "accounts": [
          {
            "name": "movieReview",
            "isMut": true,
            "isSigner": false,
            "pda": {
              "seeds": [
                {
                  "kind": "arg",
                  "type": "string",
                  "path": "title"
                },
                {
                  "kind": "account",
                  "type": "publicKey",
                  "path": "initializer"
                }
              ]
            }
          },
          {
            "name": "initializer",
            "isMut": true,
            "isSigner": true
          },
          {
            "name": "systemProgram",
            "isMut": false,
            "isSigner": false
          }
        ],
        "args": [
          {
            "name": "title",
            "type": "string"
          },
          {
            "name": "description",
            "type": "string"
          },
          {
            "name": "rating",
            "type": "u8"
          }
        ]
      },
      {
        "name": "updateMovieReview",
        "accounts": [
          {
            "name": "movieReview",
            "isMut": true,
            "isSigner": false,
            "pda": {
              "seeds": [
                {
                  "kind": "arg",
                  "type": "string",
                  "path": "title"
                },
                {
                  "kind": "account",
                  "type": "publicKey",
                  "path": "initializer"
                }
              ]
            }
          },
          {
            "name": "initializer",
            "isMut": true,
            "isSigner": true
          },
          {
            "name": "systemProgram",
            "isMut": false,
            "isSigner": false
          }
        ],
        "args": [
          {
            "name": "title",
            "type": "string"
          },
          {
            "name": "description",
            "type": "string"
          },
          {
            "name": "rating",
            "type": "u8"
          }
        ]
      },
      {
        "name": "deleteMovieReview",
        "accounts": [
          {
            "name": "movieReview",
            "isMut": true,
            "isSigner": false,
            "pda": {
              "seeds": [
                {
                  "kind": "arg",
                  "type": "string",
                  "path": "title"
                },
                {
                  "kind": "account",
                  "type": "publicKey",
                  "path": "initializer"
                }
              ]
            }
          },
          {
            "name": "initializer",
            "isMut": true,
            "isSigner": true
          }
        ],
        "args": [
          {
            "name": "title",
            "type": "string"
          }
        ]
      }
    ],
    "accounts": [
      {
        "name": "MovieAccountState",
        "type": {
          "kind": "struct",
          "fields": [
            {
              "name": "reviewer",
              "type": "publicKey"
            },
            {
              "name": "rating",
              "type": "u8"
            },
            {
              "name": "title",
              "type": "string"
            },
            {
              "name": "description",
              "type": "string"
            }
          ]
        }
      }
    ],
    "metadata": {
      "address": "CLA5Pk8tpcsA3RPmCYPaRNBdU6xBknRnqshsT1bKT7if"
    }
  }

报错信息

AnchorError: Error Code: AccountNotInitialized. Error Number: 3012. Error Message: The program expected this account to be already initialized.


方式二:手动构造Transaction调用

代码实现

const MOVIE_REVIEW_PROGRAM_ID = 'CLA5Pk8tpcsA3RPmCYPaRNBdU6xBknRnqshsT1bKT7if';
const movie = new Movie(
        "Just a test movie",
         "Wow what a good movie it was real great",
         5,
       );
const wallet = useWallet();
const connection = new Connection(clusterApiUrl('devnet'));
const buffer = movie.serialize();
const transaction = new Transaction();

const [pda] = await PublicKey.findProgramAddressSync(
      [Buffer.from(movie.title), wallet.publicKey.value.toBuffer()],
      new PublicKey(MOVIE_REVIEW_PROGRAM_ID)
     );

const instruction = new TransactionInstruction({
              keys: [
                  {
                      pubkey: pda,
                      isSigner: false,
                      isWritable: true,
                  },     
                  {
                      pubkey: publicKey.value,
                      isSigner: true,
                      isWritable: true
                  },   
                  {
                      pubkey: SystemProgram.programId,
                      isSigner: false,
                      isWritable: false
                  }
              ],
              data: buffer,
              programId: new PublicKey(MOVIE_REVIEW_PROGRAM_ID)
      });

transaction.add(instruction);

try {
    let txid = await sendTransaction(transaction, connection)
} catch (e) {
    alert(JSON.stringify(e))
}

对应Movie类

import * as borsh from "@project-serum/borsh"

export class Movie {
  constructor(title, description, rating) {
    this.title = title
    this.description = description
    this.rating = rating
  }

  borshInstructionSchema = borsh.struct([
    borsh.u8("variant"),
    borsh.str("title"),
    borsh.str("description"),
    borsh.u8("rating")
  ])

  static borshAccountSchema = borsh.struct([
    borsh.bool("initialized"),
    borsh.str("title"),
    borsh.str("description"),
    borsh.u8("rating")
  ])

  serialize() {
    const buffer = Buffer.alloc(1000)
    this.borshInstructionSchema.encode({ ...this, variant: 0 }, buffer)
    return buffer.slice(0, this.borshInstructionSchema.getSpan(buffer))
  }

  static deserialize(buffer) {
    if (!buffer) {
      return null
    }

    try {
      const { title, description , rating} = this.borshAccountSchema.decode(
        buffer
      )
      return new Movie(title, description, rating)
    } catch (e) {
      console.log("Deserialization error:", e)
      console.log(buffer)
      return null
    }
  }
}

报错信息

Transaction simulation failed: Error processing Instruction 0: custom program error: 0xbed(对应Anchor的AccountNotInitialized错误)


排查与修复方案

1. 核心问题定位

两种方式的报错本质都是**AccountNotInitialized**,说明程序期望的PDA账户已被初始化,或PDA生成逻辑存在偏差,也可能是指令序列化不匹配。

2. 方式一修复步骤

  • 修正IDL引用:代码中使用MyRaffle作为IDL传入anchor.Program,需替换为电影评论程序的正确IDL:
    import idl from './idl/anchor_movie_review_program.json';
    const program = new anchor.Program(idl, programId, provider);
    
  • 验证PDA生成一致性:确认wallet.publicKey.value正确获取钱包公钥(Vue钱包适配器中useWallet()返回的publicKey是Ref对象,需.value),且种子编码统一使用UTF-8(Buffer.from(movie.title)默认符合要求)。
  • 避免重复提交:若该PDA对应的评论已存在,需调用updateMovieReview而非addMovieReview。

3. 方式二修复步骤

  • 修复Borsh序列化逻辑:Anchor指令需使用8字节的指令Discriminator,而非手动指定的variant:0,修正序列化方法:
    // 获取addMovieReview指令的Discriminator
    const addMovieDiscriminator = anchor.utils.bytes.utf8.encode("addMovieReview").slice(0,8);
    
    serialize() {
      const titleBuffer = Buffer.from(this.title);
      const descBuffer = Buffer.from(this.description);
      const buffer = Buffer.alloc(8 + 4 + titleBuffer.length + 4 + descBuffer.length + 1);
      let offset = 0;
    
      // 写入指令Discriminator
      addMovieDiscriminator.copy(buffer, offset);
      offset +=8;
    
      // 写入title字符串(长度+内容)
      buffer.writeUInt32LE(titleBuffer.length, offset);
      offset +=4;
      titleBuffer.copy(buffer, offset);
      offset += titleBuffer.length;
    
      // 写入description字符串
      buffer.writeUInt32LE(descBuffer.length, offset);
      offset +=4;
      descBuffer.copy(buffer, offset);
      offset += descBuffer.length;
    
      // 写入rating
      buffer.writeUInt8(this.rating, offset);
      return buffer.slice(0, offset);
    }
    
  • 补充交易签名参数:sendTransaction需传入钱包作为签名者:
    const txid = await wallet.sendTransaction(transaction, connection);
    

4. 通用排查建议

  • 查看交易日志:在Solana Explorer搜索失败交易ID,查看程序日志细节。
  • 确认环境一致性:确保Vue应用连接的是Devnet,与本地测试环境一致。
  • 检查钱包状态:确认钱包已授权应用访问,且账户有足够SOL支付手续费。

内容的提问来源于stack exchange,提问作者kc.sol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:52:01