So if I anchor build
and then anchor deploy
on the devnet and then use anchor test --skip-build --skip-deploy
since I already built and deployed everything before, I find the first time around the all three tests pass with zero simulation errors. However second time around, I get an error during the simulation phase but the three tests in question still pass:
candid@DESKTOP-5D7VSM9:~/platform$ anchor test --skip-build --skip-deploy
Found a 'test' script in the Anchor.toml. Running it as a test suite!
Running test suite: "/home/candid/platform/Anchor.toml"
yarn run v1.22.22
warning package.json: No license field
$ /home/candid/platform/node_modules/.bin/ts-mocha -p ./tsconfig.json -t 1000000 'tests/**/*.ts'
counter
SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x0
at Connection.sendEncodedTransaction (/home/candid/platform/node_modules/@solana/web3.js/src/connection.ts:5923:13)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at Connection.sendRawTransaction (/home/candid/platform/node_modules/@solana/web3.js/src/connection.ts:5880:20)
at sendAndConfirmRawTransaction (/home/candid/platform/node_modules/@coral-xyz/anchor/src/provider.ts:370:21)
at AnchorProvider.sendAndConfirm (/home/candid/platform/node_modules/@coral-xyz/anchor/src/provider.ts:160:14)
at MethodsBuilder.rpc [as _rpcFn] (/home/candid/platform/node_modules/@coral-xyz/anchor/src/program/namespace/rpc.ts:29:16) {
logs: [
'Program AzkCnsvxXkMFSBK2H91BfeLVvRf4QQDcEjEvenD3kkNK invoke [1]',
'Program log: Instruction: Initialize',
'Program 11111111111111111111111111111111 invoke [2]',
'Allocate: account Address { address: B1PePsqbRFDUwaYkkFcpKTW1LytbJ4yq75ZwtwHvhSom, base: None } already in use',
'Program 11111111111111111111111111111111 failed: custom program error: 0x0',
'Program AzkCnsvxXkMFSBK2H91BfeLVvRf4QQDcEjEvenD3kkNK consumed 6561 of 200000 compute units',
'Program AzkCnsvxXkMFSBK2H91BfeLVvRf4QQDcEjEvenD3kkNK failed: custom program error: 0x0'
],
programErrorStack: ProgramErrorStack {
stack: [
[PublicKey [PublicKey(AzkCnsvxXkMFSBK2H91BfeLVvRf4QQDcEjEvenD3kkNK)]],
[PublicKey [PublicKey(11111111111111111111111111111111)]]
]
}
}
✔ Is initialized! (839ms)
Transaction Signature: rBK4seF4vbXEJjLz7uVGHVx27VGeejgpxgfdsLsDaac7jYjc4WJh5DeBfgesN9uqCgipiLKDL9p47rjJVtZZSYU
Count: 1
✔ Increment (720ms)
Transaction Signature: 2dntBqvUgHfdN7bh6kZEdRLrh7Bs7UADjWZcwMouBbH2hAhHGKNMdMVgGnYaV35SRkjdp2wS4tjsEEZJgi76afMr
Count after decrement: 0
✔ Decrement (540ms)
3 passing (2s)
Done in 3.87s.
Should I worry about this? It looks like it's happening because I am attempting to initialize an already initialized account. Since a constant seed is being used, the same address is being used on each test. How do I reset this without having to redeploy the contract on devnet? Or is that not possible?
Would it have any negative effect to the enduser that is interacting with the smart contract through the frontend once I implement it? They will only be able to increment or decrement the value on the frontend.
Here is my Rust on chain code:
use anchor_lang::prelude::*;
declare_id!("AzkCnsvxXkMFSBK2H91BfeLVvRf4QQDcEjEvenD3kkNK");
#[program]
pub mod platform {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.bump = ctx.bumps.counter; // store bump seed in `Counter` account
msg!("Counter account created! Current count: {}", counter.count);
msg!("Counter bump: {}", counter.bump);
Ok(())
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
msg!("Previous counter: {}", counter.count);
counter.count = counter.count.checked_add(1).unwrap();
msg!("Counter incremented! Current count: {}", counter.count);
Ok(())
}
pub fn decrement(ctx: Context<Decrement>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
msg!("Previous counter: {}", counter.count);
counter.count = counter.count.checked_sub(1).ok_or(ErrorCode::CounterUnderflow)?;
msg!("Counter decremented! Current count: {}", counter.count);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub user: Signer<'info>,
// Create and initialize `Counter` account using a PDA as the address
#[account(
init,
seeds = [b"counter"], // optional seeds for pda
bump, // bump seed for pda
payer = user,
space = 8 + Counter::INIT_SPACE
)]
pub counter: Account<'info, Counter>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Increment<'info> {
// The address of the `Counter` account must be a PDA derived with the specified `seeds`
#[account(
mut,
seeds = [b"counter"], // optional seeds for pda
bump = counter.bump, // bump seed for pda stored in `Counter` account
)]
pub counter: Account<'info, Counter>,
}
#[derive(Accounts)]
pub struct Decrement<'info> {
#[account(
mut,
seeds = [b"counter"], // optional seeds for pda
bump = counter.bump, // bump seed for pda stored in `Counter` account
)]
pub counter: Account<'info, Counter>,
}
// Add this error code to handle underflow when decrementing
#[error_code]
pub enum ErrorCode {
#[msg("The counter cannot be decremented below zero.")]
CounterUnderflow,
}
#[account]
#[derive(InitSpace)]
pub struct Counter {
pub count: u64, // 8 bytes
pub bump: u8, // 1 byte
}
Here is my typescript for Anchor Test:
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Platform } from "../target/types/platform";
import { PublicKey } from "@solana/web3.js";
describe("counter", () => {
// Configure the client to use the local cluster.
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.Platform as Program<Platform>;
const wallet = provider.wallet as anchor.Wallet;
const connection = provider.connection;
const [counterPDA] = PublicKey.findProgramAddressSync(
[Buffer.from("counter")],
program.programId
);
it("Is initialized!", async () => {
try {
const txSig = await program.methods.initialize().rpc();
const accountData = await program.account.counter.fetch(counterPDA);
console.log(`Transaction Signature: ${txSig}`);
console.log(`Count: ${accountData.count}`);
} catch (error) {
// If PDA Account already created, then we expect an error
console.log(error);
}
});
it("Increment", async () => {
const transactionSignature = await program.methods.increment().rpc();
const accountData = await program.account.counter.fetch(counterPDA);
console.log(`Transaction Signature: ${transactionSignature}`);
console.log(`Count: ${accountData.count}`);
});
it("Decrement", async () => {
// Now call the decrement method
const transactionSignature = await program.methods.decrement().rpc();
// Fetch the updated account data
const accountData = await program.account.counter.fetch(counterPDA);
console.log(`Transaction Signature: ${transactionSignature}`);
console.log(`Count after decrement: ${accountData.count}`);
});
});
I am using Anchor 0.29.0 because I'm still unable to get 0.30.0 to interface correctly with my frontend, but 0.29.0 works fine.