3

It seems that Anchor isn't using default values on enums.

I create an account containing an enum with a Default, and don't set a value on that enum. Example lib.rs:

#![feature(derive_default_enum)]
use anchor_lang::prelude::*;

// This is your program's public key and it will update
// automatically when you build the project.
declare_id!("HENtWdUyz7yv1rkopkt4jsd1A6tgZt8QPkKuk7KtqFb7");

#[program]
mod hello_anchor {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Initialized!");
        Ok(())
    }
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
pub enum Hello {
    X,
    #[default]
    Y,
}

#[account]
pub struct HelloAccount {
    data: Hello
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 100)]
    pub hello_account: Account<'info, HelloAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Playground link: https://beta.solpg.io/630dd93888a7fca897ad7d0a

If I call the initialize method, and then fetch the created account it has this structure:

{
  "data": {
    "x": {}
  }
}

I'd have expected it to have the y value since that's the default in the enum and I didn't set it.

Similarly if I create an account containing an array of these enums. Example lib.rs:

#![feature(derive_default_enum)]
use anchor_lang::prelude::*;

// This is your program's public key and it will update
// automatically when you build the project.
declare_id!("995YWZuGkLpcC6Q8itToMhJrnaYwwLTzUViWdui8eJU2");

#[program]
mod hello_anchor {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Initialized!");
        Ok(())
    }
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Default)]
pub enum Hello {
    X,
    #[default]
    Y,
}

#[account]
pub struct HelloAccount {
    data: [Hello; 3]
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 100)]
    pub hello_account: Account<'info, HelloAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Playground link: beta.solpg.io/630dda3c88a7fca897ad7d0b

Again I call initialize and fetch the created account. It looks like this:

{
  "data": [
    {
      "x": {}
    },
    {
      "x": {}
    },
    {
      "x": {}
    }
  ]
}

Again the array is initialized with all x values when the default is y.

Is there a way to get Anchor to initialize using the default value?

Also note that in the second case (with the array), there's a rust compile error if Default is not derived for the enum, which is fixed when I derive it. There's also a rust compile error if I have the Default derive and don't include the #[default]. So I'm not sure what I'm missing here.

Edit: I've also opened a bug in the Anchor repo: https://github.com/coral-xyz/anchor/issues/2159

2 Answers 2

2

TL;DR -- You will still need to set the initial values you want manually in the body of your instruction that creates the account.

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let hello_account = &mut ctx.accounts.hello_account;
        hello_account.data = [Hello::Y, Hello::Y, Hello::Y];
        msg!("Initialized!");
        Ok(())
    }

The reason this is happening is because account data is initialized as all zeroes (and your X variant corresponds to zero), and the Rust types you're using are an abstraction over account data that the Solana runtime knows nothing about. So by itself, the create_account instruction therefore cannot even in principle know how to populate default account data. You'll have to manually specify that in your Anchor code.

1

I believe you have to implement (impl) default for each enum you want to use default values for.

#[account]
#[derive(Default)]
pub struct HelloAccount {
    data: Hello
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy)]
pub enum Hello {
    X,
    Y,
}

impl Default for Hello {
  fn default() -> Self {
    Hello::Y
  }
}
3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.