如何在非Anchor的JS代码中获取Anchor账户的鉴别器?
问题:如何在不引入Anchor库的JS代码中生成Anchor账户/指令的鉴别器
我有如下Anchor合约代码:
use anchor_lang::prelude::*; declare_id!("kek"); #[constant] pub const MEDIA_TAG: &[u8] = b"MEDIA_STATE"; #[account] #[derive(Default)] pub struct MediaState { pub authority: Pubkey, pub name: String, } #[program] pub mod publisher { use super::*; pub fn create_media(ctx: Context<CreateMedia>, name: String) -> Result<()> { msg!("Media name: {}", name); let media_state = &mut ctx.accounts.media_state; media_state.authority = ctx.accounts.authority.key(); media_state.name = name; msg!("Media created"); Ok(()) } } #[derive(Accounts)] #[instruction()] pub struct CreateMedia<'info> { #[account(mut)] pub authority: Signer<'info>, #[account( init, seeds = [MEDIA_TAG, authority.key().as_ref()], bump, payer = authority, space = 8 + std::mem::size_of::<MediaState>(), )] pub media_state: Box<Account<'info, MediaState>>, pub system_program: Program<'info, System>, }
我希望在不引入Anchor库的JavaScript代码中,获取MediaState账户或CreateMedia指令的鉴别器,用于getProgramAccounts的过滤查询:
const publisher = new web3.PublicKey( "kek" ); const connection = new web3.Connection(web3.clusterApiUrl("devnet")); const accounts = await connection.getProgramAccounts(publisher, { filters: [{ memcmp: { offset: 0, bytes: ?????????? } }], });
目前我通过SolanaPlayground的网络开发者工具拿到了可用的鉴别器值"FtoqZ3bt1he",但不知道如何自行生成该值,特此求助。
解决方案
1. 生成MediaState账户鉴别器
Anchor的账户鉴别器是对账户结构体名称按固定规则哈希后取前8字节得到的,具体步骤:
- 构造字符串:
account:MediaState(格式为account:结构体名称) - 对该字符串做SHA-256哈希
- 取哈希结果的前8字节,再转成Base58编码
在JavaScript中可通过原生crypto模块和bs58包实现:
const crypto = require('crypto'); const bs58 = require('bs58'); // 生成MediaState账户鉴别器 const accountDiscriminator = crypto.createHash('sha256') .update(Buffer.from('account:MediaState')) .digest() .slice(0, 8); console.log(bs58.encode(accountDiscriminator)); // 输出即为你拿到的"FtoqZ3bt1he"
2. 生成CreateMedia指令鉴别器
指令鉴别器的生成逻辑类似,规则是对指令的完整标识做哈希取前8字节:
- 构造字符串:
global:publisher:create_media(格式为global:模块名:方法名) - 对该字符串做SHA-256哈希
- 取前8字节转Base58编码
代码实现:
const crypto = require('crypto'); const bs58 = require('bs58'); // 生成CreateMedia指令鉴别器 const instructionDiscriminator = crypto.createHash('sha256') .update(Buffer.from('global:publisher:create_media')) .digest() .slice(0, 8); console.log(bs58.encode(instructionDiscriminator));
核心规则总结
- 账户鉴别器:
sha256("account:结构体名称")的前8字节,转Base58 - 指令鉴别器:
sha256("global:模块名:方法名")的前8字节,转Base58
生成后的值即可直接填入getProgramAccounts的memcmp.bytes字段中使用。
内容的提问来源于stack exchange,提问作者keker
相关产品推荐
相关产品推荐

