Mutation
EVM
contract Counter {
  mapping(address user => uint256 count) public counter;
  
  function increment(address to, uint256 amount) external {
    counter[to] += amount;
  }
}Solana
First time
The flag init or init_if_needed is required to initialize the Counter account.
Notes on some terminologies:
seeds - It is used to derive the address (Program Derived Address). It can be static or dynamic and it can contain multiple elements
seeds::program - It is used to derive the address for other programs
bump - Bump seed is a provided value that ensures the account's address is off the Ed25519 curve. An address that's off the curve does not have a corresponding private key
space - Each account occupies some space and it tells Solana how much space is needed. There is always an extra 8 bytes for Anchor Discriminator. This post explains it well.
#[account]
pub struct Counter {
  pub user: Pubkey,
  pub count: u64,
}
#[derive(Accounts)]
pub struct Increment {
  #[account(init, seeds = [b"user", user.key()], bump, space = 8 + 32 + 8)
  pub counter: Account<'info, Counter>,
  
  pub user: Signer<'info>,
}
pub fn increment(ctx: Context<Increment>, amount: u64) -> Result<()> {
  ctx.accounts.counter = ctx.accounts.counter.checked_add(amount).unwrap();
  Ok(())
}Not the first time
The flag mut is required to let Solana know that the account is mutable. The program will fail silently if the flag is not present!
#[account]
pub struct Counter {
  pub user: Pubkey,
  pub count: u64,
}
#[derive(Accounts)]
pub struct Increment {
  #[account(mut, seeds = [b"user", user.key()])
  pub counter: Account<'info, Counter>,
  
  pub user: Signer<'info>,
}
pub fn increment(ctx: Context<Increment>, amount: u64) -> Result<()> {
  ctx.accounts.counter = ctx.accounts.counter.checked_add(amount).unwrap();
  Ok(())
}Last updated