如何在Localnet用Anchor测试Metaplex指令?遇执行账户错误
问题1:Localnet测试Metaplex Metadata程序部署错误
你遇到的instruction expected an executable account错误确实是因为Localnet默认未部署Metaplex Metadata程序(固定地址为metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s),需要手动将其加载到本地测试节点,具体两种方法:
方法一:启动测试节点时直接克隆Devnet的Metadata程序
运行命令:solana-test-validator --url https://api.devnet.solana.com --clone metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s该命令会从Devnet拉取Metadata程序并部署到本地节点,启动后即可正常调用
create_metadata_accounts_v3指令。方法二:Metaplex CLI部署(需先安装Metaplex CLI)
先启动本地节点:solana-test-validator再执行部署命令:
metaplex metadata deploy --cluster localnet
同时要确保Anchor程序中正确引用Metadata程序ID,示例代码片段:
use anchor_spl::metadata::{create_metadata_accounts_v3, Metadata, MetadataAccount}; use anchor_spl::token::Mint; declare_id!("你的程序ID"); #[program] pub mod nft_collection { use super::*; pub fn mint_nft(ctx: Context<MintNft>, name: String, symbol: String, uri: String) -> Result<()> { create_metadata_accounts_v3( ctx.accounts.metadata_program.to_account_info(), ctx.accounts.metadata.to_account_info(), ctx.accounts.mint.to_account_info(), ctx.accounts.mint_authority.to_account_info(), ctx.accounts.payer.to_account_info(), ctx.accounts.update_authority.to_account_info(), name, symbol, uri, None, 0, true, false, None, None, )?; Ok(()) } } #[derive(Accounts)] pub struct MintNft<'info> { #[account(mut)] pub payer: Signer<'info>, pub mint_authority: Signer<'info>, #[account( init, payer = payer, mint::decimals = 0, mint::authority = mint_authority, mint::freeze_authority = mint_authority, )] pub mint: Account<'info, Mint>, #[account( init, payer = payer, seeds = [b"metadata", metadata_program.key().as_ref(), mint.key().as_ref()], bump, space = Metadata::LEN, )] pub metadata: Account<'info, Metadata>, /// CHECK: 验证为Metaplex Metadata程序固定地址 #[account(address = metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s)] pub metadata_program: UncheckedAccount<'info>, pub system_program: Program<'info, System>, pub token_program: Program<'info, Token>, pub rent: Sysvar<'info, Rent>, }
问题2:Devnet重复部署需修改程序ID的问题
Anchor默认支持程序升级,无需每次重新部署新程序生成新ID,解决方法如下:
使用
anchor upgrade升级已有程序
确保Anchor.toml中programs.devnet下的程序ID为之前部署的固定ID,然后运行升级命令:anchor upgrade --program-id 你的程序ID target/deploy/你的程序名.so升级后程序ID不变,已初始化的账户可继续使用。
测试脚本复用已初始化账户
在测试代码中通过try_find_program_address查找已存在的集合/管理员账户,避免重复创建,示例TypeScript代码片段:import * as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; import { NftCollection } from "../target/types/nft_collection"; describe("nft-collection", () => { const provider = anchor.AnchorProvider.env(); anchor.setProvider(provider); // 直接指定已部署的程序ID const program = new Program<NftCollection>( require("../target/idl/nft_collection.json"), new anchor.web3.PublicKey("你的程序ID"), provider ); // 尝试查找已存在的集合账户 const [collectionAccount] = anchor.web3.PublicKey.findProgramAddressSync( [Buffer.from("collection"), provider.wallet.publicKey.toBuffer()], program.programId ); // 测试逻辑:如果账户已初始化则直接使用,否则创建 // ... });避免不必要的重新部署
只有当程序结构发生重大变更(如账户结构修改导致无法兼容升级)时,才需要重新部署新程序,否则优先使用升级流程。
内容的提问来源于stack exchange,提问作者Lê Văn Anh Tú
相关产品推荐
相关产品推荐

