使用Solnet与Solana交互创建代币时遇交易模拟失败问题
Solnet交易报错:Attempt to debit an account but found no record of a prior credit
问题描述
使用Solnet与Solana DevNet交互时,执行创建并初始化代币铸造账户的交易时触发以下错误:
Transaction simulation failed: Attempt to debit an account but found no record of a prior credit.
但通过solana-cli执行完全相同的操作时无任何问题。已验证GetRecentBlockHash和GetLatestBlockHash均能成功返回有效区块哈希,错误出现在Examples.SubmitTxSendAndLog(createAndInitializeMintToTx);代码行。
相关代码如下:
Wallet wallet = new Wallet(MnemonicWords); IRpcClient RpcClient = ClientFactory.GetClient(Cluster.DevNet); #region 创建并初始化代币铸造账户 RequestResult<ResponseValue<LatestBlockHash>> blockHash = RpcClient.GetLatestBlockHash(Solnet.Rpc.Types.Commitment.Finalized); ulong minBalanceForExemptionAcc = RpcClient.GetMinimumBalanceForRentExemption(TokenProgram.TokenAccountDataSize).Result; ulong minBalanceForExemptionMint = RpcClient.GetMinimumBalanceForRentExemption(TokenProgram.MintAccountDataSize).Result; Console.WriteLine($"免租金最低余额(账户)>> {minBalanceForExemptionAcc}"); Console.WriteLine($"免租金最低余额(铸造账户)>> {minBalanceForExemptionMint}"); Account ownerAccount = wallet.GetAccount(10); Account mintAccount = wallet.GetAccount(11); Account initialAccount = wallet.GetAccount(12); Console.WriteLine($"所有者账户: {ownerAccount}"); Console.WriteLine($"铸造账户: {mintAccount}"); Console.WriteLine($"初始代币账户: {initialAccount}"); byte[] createAndInitializeMintToTx = new TransactionBuilder(). SetRecentBlockHash(blockHash.Result.Value.Blockhash). SetFeePayer(ownerAccount). AddInstruction(SystemProgram.CreateAccount( ownerAccount, mintAccount, minBalanceForExemptionMint, TokenProgram.MintAccountDataSize, TokenProgram.ProgramIdKey)). AddInstruction(TokenProgram.InitializeMint( mintAccount.PublicKey, 2, ownerAccount.PublicKey, ownerAccount.PublicKey)). AddInstruction(SystemProgram.CreateAccount( ownerAccount, initialAccount, minBalanceForExemptionAcc, TokenProgram.TokenAccountDataSize, TokenProgram.ProgramIdKey)). AddInstruction(TokenProgram.InitializeAccount( initialAccount.PublicKey, mintAccount.PublicKey, ownerAccount.PublicKey)). AddInstruction(TokenProgram.MintTo( mintAccount.PublicKey, initialAccount.PublicKey, 1_000_000, ownerAccount)). AddInstruction(MemoProgram.NewMemo(initialAccount, "Hello from Sol.Net")). Build(new List<Account> { ownerAccount, mintAccount, initialAccount }); string createAndInitializeMintToTxSignature = Examples.SubmitTxSendAndLog(createAndInitializeMintToTx); if (!string.IsNullOrEmpty(createAndInitializeMintToTxSignature)) Examples.PollConfirmedTx(createAndInitializeMintToTxSignature); public static string SubmitTxSendAndLog(byte[] tx) { Console.WriteLine($"交易数据: {Convert.ToBase64String(tx)}"); RequestResult<ResponseValue<SimulationLogs>> txSim = RpcClient.SimulateTransaction(tx); string logs = PrettyPrintTransactionSimulationLogs(txSim.Result.Value.Logs); Console.WriteLine($"交易模拟:\n\t错误: {txSim.Result.Value.Error}\n\t日志: \n" + logs); RequestResult<string> txReq = RpcClient.SendTransaction(tx); Console.WriteLine($"交易签名: {txReq.Result}"); Console.WriteLine(txReq.Reason); return txReq.Result; }
问题分析
该错误核心是交易尝试从一个无余额/未正确初始化的账户扣款。结合你的场景,可能的原因包括:
- Memo指令签名者错误:使用
initialAccount作为Memo的签名者,但该账户是刚通过SystemProgram.CreateAccount创建的,此时它仅拥有租金豁免的SOL,且在交易执行流程中尚未完成初始化,Solana节点会误判为尝试从该账户扣款。 - 费用支付账户余额不足:虽然cli操作正常,但需确认代码中
ownerAccount(钱包第10个账户)在DevNet上的余额是否足够覆盖两个账户的租金豁免金额 + 交易手续费。 - 区块哈希的提交确认度设置过严:使用
Commitment.Finalized获取区块哈希,可能导致哈希过期(Finalized区块的确认时间较长),间接引发交易验证问题。
解决方案
1. 修改Memo指令的签名者
将Memo的签名者替换为ownerAccount(已拥有足够SOL的费用支付账户),避免从新创建的空账户发起签名:
// 原代码 // AddInstruction(MemoProgram.NewMemo(initialAccount, "Hello from Sol.Net")). // 修改后 AddInstruction(MemoProgram.NewMemo(ownerAccount, "Hello from Sol.Net")).
2. 验证费用支付账户余额
在solana-cli中执行以下命令,确认ownerAccount的地址余额:
solana balance <ownerAccount的公钥地址> --url devnet
确保余额 ≥ minBalanceForExemptionMint + minBalanceForExemptionAcc + 0.000005 SOL(手续费预留),如果不足可以通过DevNet水龙头领SOL:
solana airdrop 2 <ownerAccount的公钥地址> --url devnet
3. 调整区块哈希的提交确认度
将获取区块哈希的确认度从Finalized改为Confirmed,减少哈希过期的概率:
// 原代码 // RequestResult<ResponseValue<LatestBlockHash>> blockHash = RpcClient.GetLatestBlockHash(Solnet.Rpc.Types.Commitment.Finalized); // 修改后 RequestResult<ResponseValue<LatestBlockHash>> blockHash = RpcClient.GetLatestBlockHash(Solnet.Rpc.Types.Commitment.Confirmed);
验证修改
重新运行代码,交易模拟和发送应该能正常执行,你可以通过solana-cli查询铸造账户和代币账户的状态:
solana token-supply <mintAccount的公钥地址> --url devnet solana account <initialAccount的公钥地址> --url devnet
内容的提问来源于stack exchange,提问作者MortezaDalil
相关产品推荐
相关产品推荐

