跟随HackQuest部署counter项目,使用 Solana 官方提供的 playgroud 。这个平台让我们的部署和测试过程变得更加简便高效。
合约代码
lib.rs中复制以下代码
use anchor_lang::prelude::*;
use std::ops::DerefMut;
declare_id!("CVQCRMyzWNr8MbNhzjbfPu9YVvr97onF48Lc9ZwXotpW");
#[program]
pub mod counter {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let counter = ctx.accounts.counter.deref_mut();
let bump = ctx.bumps.counter;
*counter = Counter {
authority: *ctx.accounts.authority.key,
count: 0,
bump,
};
Ok(())
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
require_keys_eq!(
ctx.accounts.authority.key(),
ctx.accounts.counter.authority,
ErrorCode::Unauthorized
);
ctx.accounts.counter.count += 1;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = authority,
space = Counter::SIZE,
seeds = [b"counter"],
bump
)]
counter: Account<'info, Counter>,
#[account(mut)]
authority: Signer<'info>,
system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(
mut,
seeds = [b"counter"],
bump = counter.bump
)]
counter: Account<'info, Counter>,
authority: Signer<'info>,
}
#[account]
pub struct Counter {
pub authority: Pubkey,
pub count: u64,
pub bump: u8,
}
impl Counter {
pub const SIZE: usize = 8 + 32 + 8 + 1;
}
#[error_code]
pub enum ErrorCode {
#[msg("You are not authorized to perform this action.")]
Unauthorized,
}
交换代码
client.ts中复制以下代码
const wallet = pg.wallet;
const program = pg.program;
const counterSeed = Buffer.from("counter");
const counterPubkey = await web3.PublicKey.findProgramAddressSync(
[counterSeed],
pg.PROGRAM_ID
);
const initializeTx = await pg.program.methods
.initialize()
.accounts({
counter: counterPubkey[0],
authority: pg.wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.rpc();
let counterAccount = await program.account.counter.fetch(counterPubkey[0]);
console.log("account after initializing ==> ", Number(counterAccount.count));
const incrementTx = await pg.program.methods
.increment()
.accounts({
counter: counterPubkey[0],
authority: pg.wallet.publicKey,
})
.rpc();
counterAccount = await program.account.counter.fetch(counterPubkey[0]);
console.log("account after increasing ==>", Number(counterAccount.count));
部署和发布
- 切换到左侧工具栏第二个按钮并点击 build
- 点击deploy, 终端出现 “Deployment successful.” 即为部署成功。(这大约会消耗2~3个sol)
测试交互
切换到左侧第一个文件按钮并点击 Run ,运行client.ts文件,输出如图
再次执行就会开始报错
Running client…
client.ts:
Uncaught error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x0
各种求助之后,修改初始化代码,输出报错日志
try {
// Initialize account
const initializeTx = await pg.program.methods
.initialize()
.accounts({
counter: counterPubkey,
authority: pg.wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.rpc();
} catch (error) {
console.error("Error fetching counter account:", error);
}
报错日志如下:
logs:
[ 'Program CVQCRMyzWNr8MbNhzjbfPu9YVvr97onF48Lc9ZwXotpW invoke [1]',
'Program log: Instruction: Initialize',
'Program 11111111111111111111111111111111 invoke [2]',
'Allocate: account Address { address: 8sKt2NcKbN9E2SUE6E3NgfzwGi5ByBZxHQdCw27bMef1, base: None } already in use',
'Program 11111111111111111111111111111111 failed: custom program error: 0x0',
'Program CVQCRMyzWNr8MbNhzjbfPu9YVvr97onF48Lc9ZwXotpW consumed 4867 of 200000 compute units',
'Program CVQCRMyzWNr8MbNhzjbfPu9YVvr97onF48Lc9ZwXotpW failed: custom program error: 0x0' ],
programErrorStack: { stack: [ [Object], [Object] ] } }
根据日志信息,关键的错误是:
'Allocate: account Address { address: 8sKt2NcKbN9E2SUE6E3NgfzwGi5ByBZxHQdCw27bMef1, base: None } already in use'
这表示你尝试分配的账户地址 8sKt2NcKbN9E2SUE6E3NgfzwGi5ByBZxHQdCw27bMef1 已经被使用,因此无法进行新的初始化。这通常发生在你已经为该地址创建了账户,但可能在再次执行时未考虑到这一点。
修改initializeTx代码
let counterAccount;
try {
counterAccount = await program.account.counter.fetch(counterPubkey);
console.log("Counter account already exists:", counterAccount);
} catch (error) {
if (error.message.includes("Account does not exist")) {
console.log("Counter account does not exist, proceeding with initialization...");
// Initialize account
const initializeTx = await pg.program.methods
.initialize()
.accounts({
counter: counterPubkey,
authority: pg.wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.rpc();
} else {
console.error("Error fetching counter account:", error);
}
}
执行结果:
修复后完整client.ts代码
const wallet = pg.wallet;
const program = pg.program;
const counterSeed = Buffer.from("counter");
const [counterPubkey, bump] = web3.PublicKey.findProgramAddressSync(
[counterSeed],
pg.PROGRAM_ID
);
let counterAccount;
try {
counterAccount = await program.account.counter.fetch(counterPubkey);
console.log("Counter account already exists:", counterAccount);
} catch (error) {
if (error.message.includes("Account does not exist")) {
console.log(
"Counter account does not exist, proceeding with initialization..."
);
// Initialize account
const initializeTx = await pg.program.methods
.initialize()
.accounts({
counter: counterPubkey,
authority: pg.wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.rpc();
} else {
console.error("Error fetching counter account:", error);
}
}
const incrementTx = await pg.program.methods
.increment()
.accounts({
counter: counterPubkey,
authority: pg.wallet.publicKey,
})
.rpc();
counterAccount = await program.account.counter.fetch(counterPubkey);
console.log("account after increasing ==>", Number(counterAccount.count));