I'm using the Solana Playground where I deployed an anchor program that stores a counter and increments the number:
use anchor_lang::prelude::*;
declare_id!("XXXXX....");
#[program]
mod hello_anchor {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data = 42;
Ok(())
}
pub fn update(ctx: Context<Update>, data: u64) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
Ok(())
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data += 1;
Ok(())
}
pub fn decrement(ctx: Context<Decrement>) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data -= 1;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
// We must specify the space in order to initialize an account.
// First 8 bytes are default account discriminator,
// next 8 bytes come from NewAccount.data being type u64.
// (u64 = 64 bits unsigned integer = 8 bytes)
#[account(init, payer = signer, space = 8 + 8)]
pub my_account: Account<'info, NewAccount>,
#[account(mut)]
pub signer: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Update<'info> {
#[account(mut)]
pub my_account: Account<'info, NewAccount>,
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut)]
pub my_account: Account<'info, NewAccount>,
#[account(mut)]
pub signer: Signer<'info>,
}
#[derive(Accounts)]
pub struct Decrement<'info> {
#[account(mut)]
pub my_account: Account<'info, NewAccount>,
}
#[account]
pub struct NewAccount {
data: u64,
}
I'm then trying to call to it with this code that:
- calls initialize
- calls increment
- reads the user's current value
const myAccount = web3.Keypair.generate(); // Keypair for the account you're creating
try {
// First call: Initialize the account
const tx = await pg.program.methods
.initialize()
.accounts({
myAccount: myAccount.publicKey, // Public key of the account to initialize
signer: pg.wallet.publicKey, // Use the connected wallet's public key for payer
systemProgram: web3.SystemProgram.programId, // System program ID for creating the account
})
.signers([myAccount]) // Include both pg.wallet.payer and myAccount keypairs
.rpc(); // Send the transaction to the network
console.log("Transaction Signature for initialize:", tx);
// Second call: Increment the account data
const tx2 = await pg.program.methods
.increment() // Call the increment function
.accounts({
myAccount: myAccount.publicKey, // Public key of the account to increment
// signer: pg.wallet.publicKey,
})
// .signers([myAccount]) // Sign with the myAccount keypair for the update
.rpc(); // Send the transaction to the network
console.log("Transaction Signature for increment:", tx2);
// Fetch the account data to check if it has been incremented
const account = await pg.program.account.newAccount.fetch(
myAccount.publicKey
);
console.log("Account data after increment:", account.data.toString());
} catch (error) {
console.error("Error:", error);
}
My problem is that most of the time when I run this code it says everything finished successfully, but it incorrectly prints Account data after increment: 42
when it should be 43...
The weird thing is that if I mash the client play button then sometimes I can get it to print 43, but most of the time it prints 42...
Usually I would try to use a timeout somewhere to try to fix this data race kind of thing, but it seems like I can't use setTimeout in the solana playground...
Can anyone explain why this is happening and how I can get the correct thing to print out consistently?
Thanks!