Solana数据账户无法读取更新值问题求助
问题:Solana计数器交易成功但账户状态未更新
本地部署的Solana问候计数器程序,调用increment_greeting交易后区块浏览器显示成功,但无法读取到数据账户更新后的计数器值,余额转账、账户创建等操作均正常。
Solana合约代码(Rust)
use anchor_lang::prelude::*; declare_id!("8VEC1cycS5ry9aM5CBRWtxfVQBfNtWANTXXrXXmk2TXw"); #[program] pub mod hello_please { use super::*; pub fn create_greeting(ctx: Context<CreateGreeting>) -> Result<()> { let greeting_account = &mut ctx.accounts.greeting_account; greeting_account.counter = 0; Ok(()) } pub fn increment_greeting(ctx: Context<IncrementGreeting>) -> Result<()> { let greeting_account = &mut ctx.accounts.greeting_account; greeting_account.counter += 1; Ok(()) } } #[derive(Accounts)] pub struct CreateGreeting<'info> { #[account(init, payer = user, space = 8 + 8)] pub greeting_account: Account<'info, GreetingAccount>, #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct IncrementGreeting<'info> { #[account(mut)] pub greeting_account: Account<'info, GreetingAccount>, } #[account] pub struct GreetingAccount { pub counter: u64, }
IDL(JSON)
{ "address": "8VEC1cycS5ry9aM5CBRWtxfVQBfNtWANTXXrXXmk2TXw", "metadata": { "name": "hello_please", "version": "0.1.0", "spec": "0.1.0", "description": "Created with Anchor" }, "instructions": [ { "name": "create_greeting", "discriminator": [ 230, 141, 114, 135, 35, 122, 88, 117 ], "accounts": [ { "name": "greeting_account", "writable": true, "signer": true }, { "name": "user", "writable": true, "signer": true }, { "name": "system_program", "address": "11111111111111111111111111111111" } ], "args": [] }, { "name": "increment_greeting", "discriminator": [ 58, 180, 32, 32, 96, 80, 100, 213 ], "accounts": [ { "name": "greeting_account", "writable": true } ], "args": [] } ], "accounts": [ { "name": "GreetingAccount", "discriminator": [ 190, 16, 56, 57, 246, 26, 112, 24 ] } ], "types": [ { "name": "GreetingAccount", "type": { "kind": "struct", "fields": [ { "name": "counter", "type": "u64" } ] } } ]}
TypeScript调用代码
import * as anchor from "@coral-xyz/anchor"; import * as borsh from "@coral-xyz/borsh"; import { AnchorProvider, Program, Wallet, Idl, web3} from "@coral-xyz/anchor"; import idl from "./idl/hello_please.json"; async function main() { const connection = new web3.Connection("http://127.0.0.1:8899"); const providerAccount = web3.Keypair.generate(); console.log(`providerAccount.publicKey: ${providerAccount.publicKey}`); console.log(`providerAccount.secretKey: ${providerAccount.secretKey}`); const airdrop_txn = await connection.requestAirdrop(providerAccount.publicKey, 10e9); const latestBlockHash_1 = await connection.getLatestBlockhash(); await connection.confirmTransaction({ blockhash: latestBlockHash_1.blockhash, lastValidBlockHeight: latestBlockHash_1.lastValidBlockHeight, signature: airdrop_txn, }); console.log("Got Latest BlockHash"); const provider_balance = await connection.getBalance(providerAccount.publicKey); console.log(`provider_account_balance: ${provider_balance}`); const wallet = new Wallet(providerAccount); const provider = new AnchorProvider(connection, wallet, { }); anchor.setProvider(provider); console.log("provider set"); const program = new Program(idl as Idl, provider); console.log("program created"); const greetingAccount = anchor.web3.Keypair.generate(); console.log(greetingAccount.publicKey); console.log(`greetingAccount created. \r greetingAccount.publicKey: ${greetingAccount.publicKey}`); console.log(`Sending Funds to greetingAccount`); const send_funds_transaction = new web3.Transaction().add( web3.SystemProgram.transfer({ fromPubkey: providerAccount.publicKey, toPubkey: greetingAccount.publicKey, lamports: 2e9, }), ); const send_funds_signature = await web3.sendAndConfirmTransaction( connection, send_funds_transaction, [providerAccount], ); console.log('send_funds_signature', send_funds_signature); const greeting_balanace = await connection.getBalance(greetingAccount.publicKey); console.log(`Balance of Greeting Account: ${greeting_balanace}`); console.log("Before Sending Transaction: CreateGreeting"); const createGreeting_tx = await program.methods .createGreeting() .accounts({ greetingAccount: greetingAccount.publicKey, }) .signers([greetingAccount]) .rpc(); console.log("Create Greeting Transaction signature:", createGreeting_tx+"\n"); await printCounterValue(connection, greetingAccount, createGreeting_tx); console.log("Before Sending Transaction: IncrementGreeting"); const incrementGreeting_tx = await program.methods .incrementGreeting() .accounts({ greetingAccount: greetingAccount.publicKey, }) .signers([providerAccount]) .rpc(); console.log("Increment Greeting Transaction signature:", incrementGreeting_tx+"\n"); const isValid = await isValidSignature(connection, incrementGreeting_tx); console.log("Transaction Finalized: "+isValid); await printLatestBlockhash(connection, incrementGreeting_tx); console.log("Transaction Finalized: "+isValid); await printCounterValue(connection, greetingAccount, incrementGreeting_tx); console.log("Transaction Finalized: "+isValid); } main(); interface GreetingAccount { counter: anchor.BN } const isValidSignature = async (connection: anchor.web3.Connection, sig: string) => { const status = await connection.getSignatureStatus(sig, { searchTransactionHistory: true, }); return ( status.value?.err === null && status.value?.confirmationStatus === "finalized" ); }; async function printCounterValue(connection: anchor.web3.Connection, greetingAccount: anchor.web3.Keypair, txSignature: string){ const latestBlockHash = await connection.getLatestBlockhash(); await connection.confirmTransaction({ blockhash: latestBlockHash.blockhash, lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, signature: txSignature, }, 'finalized'); console.log("Got Latest BlockHash"); console.log("Transaction finalized. Retrieving updated account state..."); const accountInfo = await connection.getAccountInfo(greetingAccount.publicKey); if (accountInfo === null) { throw new Error("Error: Account not found"); } console.log("account info retrieved"); const GreetingAccountSchema = borsh.struct<GreetingAccount>([borsh.u64("counter"),]); console.log("GreetingAccount Schema constructed"); const {counter} = GreetingAccountSchema.decode(accountInfo?.data, "processed"); console.log("GreetingAccount Struct/Type constructed"); console.log("decoded counter: "+counter.toNumber()+"\n"); } async function printLatestBlockhash(connection: anchor.web3.Connection, txSignature: string){ const latestBlockHash = await connection.getLatestBlockhash(); await connection.confirmTransaction({ blockhash: latestBlockHash.blockhash, lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, signature: txSignature, }, 'finalized'); console.log("Got Latest BlockHash"); }
执行结果
providerAccount.publicKey: 3bq44nBYNvJhcwU7XED6hwUFWGWdis3j2boXgtgmNMMc providerAccount.secretKey: 117,199,146,222,123,138,144,19,26,63,129,43,202,20,26,58,240,92,210,168,65,43,214,187,6,193,156,166,24,57,33,68,38,163,116,115,157,110,105,109,102,165,156,10,252,121,205,229,42,62,247,58,83,157,174,42,88,218,94,30,51,226,173,35 Got Latest BlockHash provider_account_balance: 10000000000 provider set program created PublicKey [PublicKey(8fTkRGZMxXeccGZpX4a9JgUqPWzU1Q6FRr69JCtLVTEF)] { _bn: <BN: 71dc1fbbdced2bd2ef5bbe8a86de890fc9c6e17ec9e9a5ea1ff7693df3fd8158> } greetingAccount.publicKey: 8fTkRGZMxXeccGZpX4a9JgUqPWzU1Q6FRr69JCtLVTEF Sending Funds to greetingAccount send_funds_signature BeQFTFsf19QNUQjhDUhcnSqpkB9okuz6xFs3HpeUXGvwZ7MsvHRFEri61K4vK4ZE15RH16bGSuQXqLpCM6q97Fc Balance of Greeting Account: 2000000000 Before Sending Transaction: CreateGreeting Create Greeting Transaction signature: 3Cku7jdoZVLaWrmy6URz7GgepVvtAwq6HA5W4M9HDbUqfJcPhwsjS5uUVRhB7Z84b3iqnj6Jr1mdCqR52wrTZHxD Got Latest BlockHash Transaction finalized. Retrieving updated account state... account info retrieved GreetingAccount Schema constructed GreetingAccount Struct/Type constructed decoded counter: 0 Before Sending Transaction: IncrementGreeting Increment Greeting Transaction signature: 4yUhDhcmKCQxCgrkE6CAc9T8vStG6iENUiv1ivAPTGcmoXFcPgsnzoZe2zoRAWeABkay7cTVwgww9DknXeMALKUV Transaction Finalized: true Got Latest BlockHash Transaction Finalized: true Got Latest BlockHash Transaction finalized. Retrieving updated account state... account info retrieved GreetingAccount Schema constructed GreetingAccount Struct/Type constructed decoded counter: 0 Transaction Finalized: true
问题原因与修复方案
核心问题
Anchor创建的账户会在数据开头添加8字节的账户 discriminator,用于标识账户类型。你在TypeScript中直接用Borsh解码完整的账户数据,相当于把discriminator当成了计数器的一部分,导致解码结果错误。
修复方式1:手动跳过8字节 discriminator
修改printCounterValue函数中的解码逻辑,跳过前8字节:
async function printCounterValue(connection: anchor.web3.Connection, greetingAccount: anchor.web3.Keypair, txSignature: string){ // ... 保留原有确认交易、获取账户信息的代码 ... // 跳过前8字节的Anchor账户discriminator const {counter} = GreetingAccountSchema.decode(accountInfo.data.slice(8), "processed"); // ... 保留原有打印逻辑 ... }
修复方式2:用Anchor Program直接读取账户(推荐)
利用Anchor IDL的类型支持,直接通过Program实例读取账户,无需手动处理Borsh解码:
// 替换原printCounterValue函数 async function printCounterValue(program: Program, greetingAccountPubkey: anchor.web3.PublicKey){ const greetingAccount = await program.account.greetingAccount.fetch(greetingAccountPubkey); console.log("decoded counter: "+greetingAccount.counter.toNumber()+"\n"); } // 在main函数中调用时,传入program和账户公钥 // 创建账户后调用: await printCounterValue(program, greetingAccount.publicKey); // 增量交易后调用: await printCounterValue(program, greetingAccount.publicKey);
额外优化
IncrementGreeting交易中不需要传入providerAccount作为签名者,因为greeting_account仅需要可写权限,不需要签名(只有初始化账户时需要签名),可以去掉多余的signers参数:
const incrementGreeting_tx = await program.methods .incrementGreeting() .accounts({ greetingAccount: greetingAccount.publicKey, }) .rpc();
内容的提问来源于stack exchange,提问作者Md Tauhidul Islam
相关产品推荐
相关产品推荐

