Without constraints
Check initialized
Account::try_from
will check
- the account is owned by the correct program
- the account is initialized
- the account has the correct discriminator
and can be deserialized into the struct
let example_pda1_account_info = ctx.accounts.example_pda1.to_account_info()
let mut example_pda1: Account<ExamplePda> =
Account::try_from(example_pda1_account_info)?;
Check uninitialized
I haven't checked that this actually compiles but this is adapted from the zero discriminator check that the zero
constraint source code uses.
let mut __data: &[u8] = ctx.accounts.example_pda1.to_account_info().try_borrow_data()?;
let mut __disc_bytes = [0u8; 8];
__disc_bytes.copy_from_slice(&__data[..8]);
let __discriminator = u64::from_le_bytes(__disc_bytes);
if __discriminator != 0 {
return Err();
}
With constraints
Check initialized
To check that a program account has been initialized you can just get anchor to try and load the program account in the accounts context, similar to how you verify the account is empty above.
#[account(
seeds = [
b"some-seed",
partner1_pub.key().as_ref(),
],
bump = example_pda1.bump,
)]
pub example_pda1: Account<'info, ExamplePdaAccount>
Anchor will try to load the account data and check that the 8 bytes at the start of the account match the expected discriminator.
Check uninitialized
For checking that an account is not initialized I would instead check that the system program still owns the account. A system program account can't have data on it, though it might have some lamports in it.
#[account(
seeds = [
b"some-seed",
partner1_pub.key().as_ref(),
],
bump,
)]
pub example_pda1: SystemAccount<'info>
Finally zero
doesn't do what you expect it to do here. It does a lot more. Check out the constraints doc https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html#constraints. Essentially it checks that the 8 byte discriminator is not initialized and that the account has enough solana rent to be rent exempt (although this is now a run time requirement) but it will also check that your account is owned by the program calling the function, ensures the account is mutable, and initializes the account + the discriminator. zero
is essentially a lighter weight version of init
that needs to be called in different scenarios that are explained in the docs.
Use this constraint (zero) if you want to create an account in a previous instruction and then initialize it in your instruction instead of using init. This is necessary for accounts that are larger than 10 Kibibyte because those accounts cannot be created via a CPI (which is what init would do).