From 7d9949231f0aacc8d6d1ea43930a17e593e5b449 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 7 Mar 2022 11:23:47 -0500 Subject: [PATCH] lang: remove default space calc (#1519) --- CHANGELOG.md | 4 ++ lang/derive/accounts/src/lib.rs | 26 +++---- lang/syn/src/codegen/accounts/constraints.rs | 24 +------ lang/syn/src/lib.rs | 2 +- lang/syn/src/parser/accounts/constraints.rs | 35 ++++++---- lang/syn/src/parser/accounts/mod.rs | 3 +- .../programs/bpf-upgradeable-state/src/lib.rs | 9 ++- tests/cfo/programs/cfo/src/lib.rs | 68 ++++++++++++------- tests/ido-pool/programs/ido-pool/src/lib.rs | 64 +++++++++-------- tests/misc/programs/misc/src/account.rs | 43 ++++++++---- tests/misc/programs/misc/src/context.rs | 34 ++++++---- tests/misc/tests/misc.js | 5 +- tests/zero-copy/programs/zero-copy/src/lib.rs | 14 ++-- 13 files changed, 183 insertions(+), 148 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83931920be..563a0b82ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,10 @@ incremented for features. * cli: Fix rust template ([#1488](https://github.com/project-serum/anchor/pull/1488)). +### Breaking + +* lang: Remove space calculation using [`#[derive(Default)]`] (https://github.com/project-serum/anchor/pull/1519). + ## [0.22.0] - 2022-02-20 ### Features diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index 02704f5628..66fbdfec80 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -89,7 +89,6 @@ use syn::parse_macro_input; /// /// /// -/// #[account(init, payer = <target_account>)]

/// #[account(init, payer = <target_account>, space = <num_bytes>)] /// /// @@ -110,14 +109,12 @@ use syn::parse_macro_input; /// and be called system_program. /// ///
  • -/// Requires that the space constraint is specified -/// or, if creating an Account type, the T of Account -/// to implement the rust std Default trait.
    +/// Requires that the space constraint is specified. /// When using the space constraint, one must remember to add 8 to it -/// which is the size of the account discriminator.
    -/// The given number is the size of the account in bytes, so accounts that hold -/// a variable number of items such as a Vec should use the space -/// constraint instead of using the Default trait and allocate sufficient space for all items that may +/// which is the size of the account discriminator. This only has to be done +/// for accounts owned by anchor programs.
    +/// The given space number is the size of the account in bytes, so accounts that hold +/// a variable number of items such as a Vec should allocate sufficient space for all items that may /// be added to the data structure because account size is fixed. Check out the borsh library /// (which anchor uses under the hood for serialization) specification to learn how much /// space different data structures require. @@ -126,20 +123,13 @@ use syn::parse_macro_input; /// Example: ///
     /// #[account]
    -/// #[derive(Default)]
     /// pub struct MyData {
     ///     pub data: u64
     /// }
    
    -/// #[account]
    -/// pub struct OtherData {
    -///     pub data: u64
    -/// }
    
     /// #[derive(Accounts)]
     /// pub struct Initialize<'info> {
    -///     #[account(init, payer = payer)]
    -///     pub data_account: Account<'info, MyData>,
     ///     #[account(init, payer = payer, space = 8 + 8)]
    -///     pub data_account_two: Account<'info, OtherData>,
    +///     pub data_account_two: Account<'info, MyData>,
     ///     #[account(mut)]
     ///     pub payer: Signer<'info>,
     ///     pub system_program: Program<'info, System>,
    @@ -172,7 +162,7 @@ use syn::parse_macro_input;
     /// #[instruction(bump: u8)]
     /// pub struct Initialize<'info> {
     ///     #[account(
    -///         init, payer = payer,
    +///         init, payer = payer, space = 8 + 8
     ///         seeds = [b"example_seed".as_ref()], bump = bump
     ///     )]
     ///     pub pda_data_account: Account<'info, MyData>,
    @@ -182,7 +172,7 @@ use syn::parse_macro_input;
     ///     )]
     ///     pub account_for_other_program: AccountInfo<'info>,
     ///     #[account(
    -///         init,payer = payer, space = 8 + 8,
    +///         init, payer = payer, space = 8 + 8,
     ///         owner = other_program.key(),
     ///         seeds = [b"other_seed".as_ref()], bump
     ///     )]
    diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs
    index fc9dc79255..95afd3d1dc 100644
    --- a/lang/syn/src/codegen/accounts/constraints.rs
    +++ b/lang/syn/src/codegen/accounts/constraints.rs
    @@ -480,29 +480,7 @@ fn generate_constraint_init_group(f: &Field, c: &ConstraintInitGroup) -> proc_ma
             }
             InitKind::Program { owner } => {
                 // Define the space variable.
    -            let space = match space {
    -                // If no explicit space param was given, serialize the type to bytes
    -                // and take the length (with +8 for the discriminator.)
    -                None => {
    -                    let account_ty = f.account_ty();
    -                    match matches!(f.ty, Ty::Loader(_) | Ty::AccountLoader(_)) {
    -                        false => {
    -                            quote! {
    -                                let space = 8 + #account_ty::default().try_to_vec().unwrap().len();
    -                            }
    -                        }
    -                        true => {
    -                            quote! {
    -                                let space = 8 + anchor_lang::__private::bytemuck::bytes_of(&#account_ty::default()).len();
    -                            }
    -                        }
    -                    }
    -                }
    -                // Explicit account size given. Use it.
    -                Some(s) => quote! {
    -                    let space = #s;
    -                },
    -            };
    +            let space = quote! {let space = #space;};
     
                 // Define the owner of the account being created. If not specified,
                 // default to the currently executing program.
    diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs
    index ca652f81d5..cf00ca23ed 100644
    --- a/lang/syn/src/lib.rs
    +++ b/lang/syn/src/lib.rs
    @@ -721,7 +721,7 @@ pub enum ConstraintRentExempt {
     pub struct ConstraintInitGroup {
         pub if_needed: bool,
         pub seeds: Option,
    -    pub payer: Option,
    +    pub payer: Expr,
         pub space: Option,
         pub kind: InitKind,
     }
    diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs
    index 533d5053fc..42454fec4f 100644
    --- a/lang/syn/src/parser/accounts/constraints.rs
    +++ b/lang/syn/src/parser/accounts/constraints.rs
    @@ -505,17 +505,28 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                 }
             }
     
    -        // SPL Space.
    -        if self.init.is_some()
    -            && self.seeds.is_some()
    -            && self.token_mint.is_some()
    -            && (self.mint_authority.is_some() || self.token_authority.is_some())
    -            && self.space.is_some()
    -        {
    -            return Err(ParseError::new(
    -                self.space.as_ref().unwrap().span(),
    -                "space is not required for initializing an spl account",
    -            ));
    +        // Space.
    +        if let Some(i) = &self.init {
    +            let initializing_token_program_acc = self.token_mint.is_some()
    +                || self.mint_authority.is_some()
    +                || self.token_authority.is_some()
    +                || self.associated_token_authority.is_some();
    +
    +            match (self.space.is_some(), initializing_token_program_acc) {
    +                (true, true) => {
    +                    return Err(ParseError::new(
    +                        self.space.as_ref().unwrap().span(),
    +                        "space is not required for initializing an spl account",
    +                    ));
    +                }
    +                (false, false) => {
    +                    return Err(ParseError::new(
    +                        i.span(),
    +                        "space must be provided with init",
    +                    ));
    +                }
    +                _ => (),
    +            }
             }
     
             let ConstraintGroupBuilder {
    @@ -593,7 +604,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                 init: init.as_ref().map(|i| Ok(ConstraintInitGroup {
                     if_needed: i.if_needed,
                     seeds: seeds.clone(),
    -                payer: into_inner!(payer.clone()).map(|a| a.target),
    +                payer: into_inner!(payer.clone()).unwrap().target,
                     space: space.clone().map(|s| s.space.clone()),
                     kind: if let Some(tm) = &token_mint {
                         InitKind::Token {
    diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs
    index e375cbc159..b0178af5f5 100644
    --- a/lang/syn/src/parser/accounts/mod.rs
    +++ b/lang/syn/src/parser/accounts/mod.rs
    @@ -93,8 +93,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> {
     
             for field in init_fields {
                 // Get payer for init-ed account
    -            let associated_payer_name = match field.constraints.init.clone().unwrap().payer.unwrap()
    -            {
    +            let associated_payer_name = match field.constraints.init.clone().unwrap().payer {
                     // composite payer, check not supported
                     Expr::Field(_) => continue,
                     field_name => field_name.to_token_stream().to_string(),
    diff --git a/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs b/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs
    index 09087114d5..fca03bb7df 100644
    --- a/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs
    +++ b/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs
    @@ -32,11 +32,14 @@ pub mod bpf_upgradeable_state {
     }
     
     #[account]
    -#[derive(Default, Debug)]
     pub struct Settings {
         admin_data: u64,
     }
     
    +impl Settings {
    +    pub const LEN: usize = 8;
    +}
    +
     #[error_code]
     pub enum CustomError {
         InvalidProgramDataAddress,
    @@ -49,7 +52,7 @@ pub struct SetAdminSettings<'info> {
         // In a real program, this should be a PDA,
         // so the authority cannot create multiple settings accounts.
         // Not done here for easier testing
    -    #[account(init, payer = authority)]
    +    #[account(init, payer = authority, space = Settings::LEN + 8)]
         pub settings: Account<'info, Settings>,
         #[account(mut)]
         pub authority: Signer<'info>,
    @@ -65,7 +68,7 @@ pub struct SetAdminSettingsUseProgramState<'info> {
         // In a real program, this should be a PDA,
         // so the authority cannot create multiple settings accounts.
         // Not done here for easier testing
    -    #[account(init, payer = authority)]
    +    #[account(init, payer = authority, space = Settings::LEN + 8)]
         pub settings: Account<'info, Settings>,
         #[account(mut)]
         pub authority: Signer<'info>,
    diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs
    index 959cc25f5c..480cb04ece 100644
    --- a/tests/cfo/programs/cfo/src/lib.rs
    +++ b/tests/cfo/programs/cfo/src/lib.rs
    @@ -324,6 +324,7 @@ pub struct CreateOfficer<'info> {
             seeds = [dex_program.key.as_ref()],
             bump,
             payer = authority,
    +        space = Officer::LEN + 8
         )]
         officer: Box>,
         #[account(
    @@ -332,7 +333,7 @@ pub struct CreateOfficer<'info> {
             bump,
             payer = authority,
             token::mint = srm_mint,
    -        token::authority = officer,
    +        token::authority = officer
         )]
         srm_vault: Box>,
         #[account(
    @@ -341,7 +342,7 @@ pub struct CreateOfficer<'info> {
             bump,
             payer = authority,
             token::mint = usdc_mint,
    -        token::authority = officer,
    +        token::authority = officer
         )]
         usdc_vault: Box>,
         #[account(
    @@ -350,7 +351,7 @@ pub struct CreateOfficer<'info> {
             bump,
             payer = authority,
             token::mint = srm_mint,
    -        token::authority = officer,
    +        token::authority = officer
         )]
         stake: Box>,
         #[account(
    @@ -359,7 +360,7 @@ pub struct CreateOfficer<'info> {
             bump,
             payer = authority,
             token::mint = srm_mint,
    -        token::authority = officer,
    +        token::authority = officer
         )]
         treasury: Box>,
         #[account(mut)]
    @@ -392,6 +393,7 @@ pub struct AuthorizeMarket<'info> {
             payer = payer,
             seeds = [b"market-auth", officer.key().as_ref(), market.key.as_ref()],
             bump,
    +        space = MarketAuth::LEN + 8
         )]
         market_auth: Account<'info, MarketAuth>,
         #[account(mut)]
    @@ -421,7 +423,7 @@ pub struct CreateOfficerToken<'info> {
             bump,
             token::mint = mint,
             token::authority = officer,
    -        payer = payer,
    +        payer = payer
         )]
         token: Account<'info, TokenAccount>,
         mint: Account<'info, Mint>,
    @@ -666,28 +668,31 @@ pub struct DropStakeRewardPool<'info> {
     ///
     /// PDA - [dex_program_id].
     #[account]
    -#[derive(Default)]
     pub struct Officer {
         // Priviledged account.
    -    pub authority: Pubkey,
    +    pub authority: Pubkey, // 32
         // Vault holding the officer's SRM tokens prior to distribution.
    -    pub srm_vault: Pubkey,
    +    pub srm_vault: Pubkey, // 32
         // Escrow SRM vault holding tokens which are dropped onto stakers.
    -    pub stake: Pubkey,
    +    pub stake: Pubkey, // 32
         // SRM token account to send treasury earned tokens to.
    -    pub treasury: Pubkey,
    +    pub treasury: Pubkey, // 32
         // Defines the fee distribution, i.e., what percent each fee category gets.
    -    pub distribution: Distribution,
    +    pub distribution: Distribution, // Distribution::LEN
         // Swap frontend for the dex.
    -    pub swap_program: Pubkey,
    +    pub swap_program: Pubkey, // 32
         // Dex program the officer is associated with.
    -    pub dex_program: Pubkey,
    +    pub dex_program: Pubkey, // 32
         // SRM stake pool address
    -    pub registrar: Pubkey,
    +    pub registrar: Pubkey, // 32
         // MSRM stake pool address.
    -    pub msrm_registrar: Pubkey,
    +    pub msrm_registrar: Pubkey, // 32
         // Bump seeds for pdas.
    -    pub bumps: OfficerBumps,
    +    pub bumps: OfficerBumps, // OfficerBumps::LEN
    +}
    +
    +impl Officer {
    +    pub const LEN: usize = 8 * 32 + Distribution::LEN + OfficerBumps::LEN;
     }
     
     /// MarketAuth represents an authorization token created by the Officer
    @@ -702,26 +707,37 @@ pub struct Officer {
     ///
     /// PDA - [b"market-auth", officer, market_address]
     #[account]
    -#[derive(Default)]
     pub struct MarketAuth {
         // Bump seed for this account's PDA.
    -    pub bump: u8,
    +    pub bump: u8, // 1
    +}
    +
    +impl MarketAuth {
    +    pub const LEN: usize = 1;
     }
     
     #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
     pub struct OfficerBumps {
    -    pub bump: u8,
    -    pub srm: u8,
    -    pub usdc: u8,
    -    pub stake: u8,
    -    pub treasury: u8,
    +    pub bump: u8,     // 1
    +    pub srm: u8,      // 1
    +    pub usdc: u8,     // 1
    +    pub stake: u8,    // 1
    +    pub treasury: u8, // 1
    +}
    +
    +impl OfficerBumps {
    +    pub const LEN: usize = 5;
     }
     
     #[derive(AnchorSerialize, AnchorDeserialize, Default, Clone)]
     pub struct Distribution {
    -    burn: u8,
    -    stake: u8,
    -    treasury: u8,
    +    burn: u8,     // 1
    +    stake: u8,    // 1
    +    treasury: u8, // 1
    +}
    +
    +impl Distribution {
    +    pub const LEN: usize = 3;
     }
     
     // CpiContext transformations.
    diff --git a/tests/ido-pool/programs/ido-pool/src/lib.rs b/tests/ido-pool/programs/ido-pool/src/lib.rs
    index 2a2abfb7ed..ca7b0320fb 100644
    --- a/tests/ido-pool/programs/ido-pool/src/lib.rs
    +++ b/tests/ido-pool/programs/ido-pool/src/lib.rs
    @@ -295,7 +295,9 @@ pub struct InitializePool<'info> {
         #[account(init,
             seeds = [ido_name.as_bytes()],
             bump,
    -        payer = ido_authority)]
    +        payer = ido_authority,
    +        space = IdoAccount::LEN + 8
    +    )]
         pub ido_account: Box>,
         // TODO Confirm USDC mint address on mainnet or leave open as an option for other stables
         #[account(constraint = usdc_mint.decimals == DECIMALS)]
    @@ -305,7 +307,8 @@ pub struct InitializePool<'info> {
             mint::authority = ido_account,
             seeds = [ido_name.as_bytes(), b"redeemable_mint".as_ref()],
             bump,
    -        payer = ido_authority)]
    +        payer = ido_authority
    +    )]
         pub redeemable_mint: Box>,
         #[account(constraint = watermelon_mint.key() == ido_authority_watermelon.mint)]
         pub watermelon_mint: Box>,
    @@ -314,14 +317,16 @@ pub struct InitializePool<'info> {
             token::authority = ido_account,
             seeds = [ido_name.as_bytes(), b"pool_watermelon"],
             bump,
    -        payer = ido_authority)]
    +        payer = ido_authority
    +    )]
         pub pool_watermelon: Box>,
         #[account(init,
             token::mint = usdc_mint,
             token::authority = ido_account,
             seeds = [ido_name.as_bytes(), b"pool_usdc"],
             bump,
    -        payer = ido_authority)]
    +        payer = ido_authority
    +    )]
         pub pool_usdc: Box>,
         // Programs and Sysvars
         pub system_program: Program<'info, System>,
    @@ -341,7 +346,8 @@ pub struct InitUserRedeemable<'info> {
                 ido_account.ido_name.as_ref().trim_ascii_whitespace(),
                 b"user_redeemable"],
             bump,
    -        payer = user_authority)]
    +        payer = user_authority
    +    )]
         pub user_redeemable: Box>,
         // IDO Accounts
         #[account(seeds = [ido_account.ido_name.as_ref().trim_ascii_whitespace()],
    @@ -401,7 +407,8 @@ pub struct InitEscrowUsdc<'info> {
                 ido_account.ido_name.as_ref().trim_ascii_whitespace(),
                 b"escrow_usdc"],
             bump,
    -        payer = user_authority)]
    +        payer = user_authority
    +    )]
         pub escrow_usdc: Box>,
         #[account(seeds = [ido_account.ido_name.as_ref().trim_ascii_whitespace()],
             bump = ido_account.bumps.ido_account,
    @@ -541,36 +548,39 @@ pub struct WithdrawFromEscrow<'info> {
     }
     
     #[account]
    -#[derive(Default)]
     pub struct IdoAccount {
    -    pub ido_name: [u8; 10], // Setting an arbitrary max of ten characters in the ido name.
    -    pub bumps: PoolBumps,
    -    pub ido_authority: Pubkey,
    -
    -    pub usdc_mint: Pubkey,
    -    pub redeemable_mint: Pubkey,
    -    pub watermelon_mint: Pubkey,
    -    pub pool_usdc: Pubkey,
    -    pub pool_watermelon: Pubkey,
    -
    -    pub num_ido_tokens: u64,
    -    pub ido_times: IdoTimes,
    +    pub ido_name: [u8; 10], // Setting an arbitrary max of ten characters in the ido name. // 10
    +    pub bumps: PoolBumps,   // 4
    +    pub ido_authority: Pubkey, // 32
    +
    +    pub usdc_mint: Pubkey,       // 32
    +    pub redeemable_mint: Pubkey, // 32
    +    pub watermelon_mint: Pubkey, // 32
    +    pub pool_usdc: Pubkey,       // 32
    +    pub pool_watermelon: Pubkey, // 32
    +
    +    pub num_ido_tokens: u64, // 8
    +    pub ido_times: IdoTimes, // 32
    +}
    +
    +impl IdoAccount {
    +    pub const LEN: usize = 10 + 4 + 32 + 5 * 32 + 8 + 32;
     }
     
     #[derive(AnchorSerialize, AnchorDeserialize, Default, Clone, Copy)]
     pub struct IdoTimes {
    -    pub start_ido: i64,
    -    pub end_deposits: i64,
    -    pub end_ido: i64,
    -    pub end_escrow: i64,
    +    pub start_ido: i64,    // 8
    +    pub end_deposits: i64, // 8
    +    pub end_ido: i64,      // 8
    +    pub end_escrow: i64,   // 8
     }
     
     #[derive(AnchorSerialize, AnchorDeserialize, Default, Clone)]
     pub struct PoolBumps {
    -    pub ido_account: u8,
    -    pub redeemable_mint: u8,
    -    pub pool_watermelon: u8,
    -    pub pool_usdc: u8,
    +    pub ido_account: u8,     // 1
    +    pub redeemable_mint: u8, // 1
    +    pub pool_watermelon: u8, // 1
    +    pub pool_usdc: u8,       // 1
     }
     
     #[error_code]
    diff --git a/tests/misc/programs/misc/src/account.rs b/tests/misc/programs/misc/src/account.rs
    index b94e1fdcf4..4a5fc13c5c 100644
    --- a/tests/misc/programs/misc/src/account.rs
    +++ b/tests/misc/programs/misc/src/account.rs
    @@ -1,50 +1,63 @@
     use anchor_lang::prelude::*;
     
    +macro_rules! size {
    +    ($name: ident, $size:expr) => {
    +        impl $name {
    +            pub const LEN: usize = $size;
    +        }
    +    };
    +}
    +
     pub const MAX_SIZE: usize = 10;
     
     #[account]
     pub struct Data {
    -    pub udata: u128,
    -    pub idata: i128,
    +    pub udata: u128, // 16
    +    pub idata: i128, // 16
     }
    +size!(Data, 32);
     
     #[account]
    -#[derive(Default)]
     pub struct DataU16 {
    -    pub data: u16,
    +    pub data: u16, // 2
     }
    +size!(DataU16, 32);
     
     #[account]
    -#[derive(Default)]
     pub struct DataI8 {
    -    pub data: i8,
    +    pub data: i8, // 1
     }
    +size!(DataI8, 1);
     
     #[account]
     pub struct DataI16 {
    -    pub data: i16,
    +    pub data: i16, // 2
     }
    +size!(DataI16, 2);
     
     #[account(zero_copy)]
    -#[derive(Default)]
     pub struct DataZeroCopy {
    -    pub data: u16,
    -    pub bump: u8,
    +    pub data: u16,    // 2
    +    pub _padding: u8, // 1
    +    pub bump: u8,     // 1
     }
    +size!(DataZeroCopy, 4);
     
     #[account]
    -#[derive(Default)]
     pub struct DataWithFilter {
    -    pub authority: Pubkey,
    -    pub filterable: Pubkey,
    +    pub authority: Pubkey,  // 32
    +    pub filterable: Pubkey, // 32
     }
    +size!(DataWithFilter, 64);
     
     #[account]
     pub struct DataMultidimensionalArray {
    -    pub data: [[u8; 10]; 10],
    +    pub data: [[u8; 10]; 10], // 100
     }
    +size!(DataMultidimensionalArray, 100);
     
     #[account]
     pub struct DataConstArraySize {
    -    pub data: [u8; MAX_SIZE],
    +    pub data: [u8; MAX_SIZE], // 10
     }
    +size!(DataConstArraySize, MAX_SIZE);
    diff --git a/tests/misc/programs/misc/src/context.rs b/tests/misc/programs/misc/src/context.rs
    index cda496cbe8..e34c6c71eb 100644
    --- a/tests/misc/programs/misc/src/context.rs
    +++ b/tests/misc/programs/misc/src/context.rs
    @@ -16,15 +16,17 @@ pub struct TestTokenSeedsInit<'info> {
             payer = authority,
             mint::decimals = 6,
             mint::authority = authority,
    +        
         )]
         pub mint: Account<'info, Mint>,
         #[account(
             init,
    -        seeds = [b"my-token-seed".as_ref(),],
    +        seeds = [b"my-token-seed".as_ref()],
             bump,
             payer = authority,
             token::mint = mint,
             token::authority = authority,
    +        
         )]
         pub my_pda: Account<'info, TokenAccount>,
         #[account(mut)]
    @@ -42,6 +44,7 @@ pub struct TestInitAssociatedToken<'info> {
             payer = payer,
             associated_token::mint = mint,
             associated_token::authority = payer,
    +        
         )]
         pub token: Account<'info, TokenAccount>,
         pub mint: Account<'info, Mint>,
    @@ -86,6 +89,7 @@ pub struct TestPdaInit<'info> {
             seeds = [b"my-seed", domain.as_bytes(), foo.key.as_ref(), &seed],
             bump,
             payer = my_payer,
    +        space = DataU16::LEN + 8
         )]
         pub my_pda: Account<'info, DataU16>,
         #[account(mut)]
    @@ -102,8 +106,9 @@ pub struct TestPdaInitZeroCopy<'info> {
             seeds = [b"my-seed".as_ref()],
             bump,
             payer = my_payer,
    +        space = DataZeroCopy::LEN + 8
         )]
    -    pub my_pda: Loader<'info, DataZeroCopy>,
    +    pub my_pda: AccountLoader<'info, DataZeroCopy>,
         #[account(mut)]
         pub my_payer: Signer<'info>,
         pub system_program: Program<'info, System>,
    @@ -116,7 +121,7 @@ pub struct TestPdaMutZeroCopy<'info> {
             seeds = [b"my-seed".as_ref()],
             bump = my_pda.load()?.bump,
         )]
    -    pub my_pda: Loader<'info, DataZeroCopy>,
    +    pub my_pda: AccountLoader<'info, DataZeroCopy>,
         /// CHECK:
         pub my_payer: AccountInfo<'info>,
     }
    @@ -204,7 +209,7 @@ pub struct TestI8<'info> {
     
     #[derive(Accounts)]
     pub struct TestInit<'info> {
    -    #[account(init, payer = payer)]
    +    #[account(init, payer = payer, space = DataI8::LEN + 8)]
         pub data: Account<'info, DataI8>,
         #[account(mut)]
         pub payer: Signer<'info>,
    @@ -213,7 +218,7 @@ pub struct TestInit<'info> {
     
     #[derive(Accounts)]
     pub struct TestInitZeroCopy<'info> {
    -    #[account(init, payer = payer, space = 8 + size_of::())]
    +    #[account(init, payer = payer, space = DataZeroCopy::LEN + 8)]
         pub data: Loader<'info, DataZeroCopy>,
         #[account(mut)]
         pub payer: Signer<'info>,
    @@ -222,7 +227,7 @@ pub struct TestInitZeroCopy<'info> {
     
     #[derive(Accounts)]
     pub struct TestInitMint<'info> {
    -    #[account(init, mint::decimals = 6, mint::authority = payer, mint::freeze_authority = payer, payer = payer)]
    +    #[account(init, mint::decimals = 6, mint::authority = payer, mint::freeze_authority = payer, payer = payer, )]
         pub mint: Account<'info, Mint>,
         #[account(mut)]
         pub payer: Signer<'info>,
    @@ -233,7 +238,7 @@ pub struct TestInitMint<'info> {
     
     #[derive(Accounts)]
     pub struct TestInitToken<'info> {
    -    #[account(init, token::mint = mint, token::authority = payer, payer = payer)]
    +    #[account(init, token::mint = mint, token::authority = payer, payer = payer, )]
         pub token: Account<'info, TokenAccount>,
         pub mint: Account<'info, Mint>,
         #[account(mut)]
    @@ -246,14 +251,14 @@ pub struct TestInitToken<'info> {
     #[derive(Accounts)]
     pub struct TestCompositePayer<'info> {
         pub composite: TestInit<'info>,
    -    #[account(init, payer = composite.payer, space = 8 + size_of::())]
    +    #[account(init, payer = composite.payer, space = Data::LEN + 8)]
         pub data: Account<'info, Data>,
         pub system_program: Program<'info, System>,
     }
     
     #[derive(Accounts)]
     pub struct TestFetchAll<'info> {
    -    #[account(init, payer = authority)]
    +    #[account(init, payer = authority, space = DataWithFilter::LEN + 8)]
         pub data: Account<'info, DataWithFilter>,
         #[account(mut)]
         pub authority: Signer<'info>,
    @@ -262,7 +267,7 @@ pub struct TestFetchAll<'info> {
     
     #[derive(Accounts)]
     pub struct TestInitWithEmptySeeds<'info> {
    -    #[account(init, seeds = [], bump, payer = authority, space = 8 + size_of::())]
    +    #[account(init, seeds = [], bump, payer = authority, space = Data::LEN + 8)]
         pub pda: Account<'info, Data>,
         #[account(mut)]
         pub authority: Signer<'info>,
    @@ -278,7 +283,7 @@ pub struct TestEmptySeedsConstraint<'info> {
     
     #[derive(Accounts)]
     pub struct InitWithSpace<'info> {
    -    #[account(init, payer = payer)]
    +    #[account(init, payer = payer, space = DataU16::LEN + 8)]
         pub data: Account<'info, DataU16>,
         #[account(mut)]
         pub payer: Signer<'info>,
    @@ -287,7 +292,8 @@ pub struct InitWithSpace<'info> {
     
     #[derive(Accounts)]
     pub struct TestInitIfNeeded<'info> {
    -    #[account(init_if_needed, payer = payer, space = 500)]
    +    // intentionally using more space (+500) to check whether space is checked when using init_if_needed
    +    #[account(init_if_needed, payer = payer, space = DataU16::LEN + 8 + 500)]
         pub data: Account<'info, DataU16>,
         #[account(mut)]
         pub payer: Signer<'info>,
    @@ -335,7 +341,7 @@ pub struct TestInitMintIfNeeded<'info> {
     
     #[derive(Accounts)]
     pub struct TestInitTokenIfNeeded<'info> {
    -    #[account(init_if_needed, token::mint = mint, token::authority = authority, payer = payer)]
    +    #[account(init_if_needed, token::mint = mint, token::authority = authority, payer = payer, )]
         pub token: Account<'info, TokenAccount>,
         pub mint: Account<'info, Mint>,
         #[account(mut)]
    @@ -353,7 +359,7 @@ pub struct TestInitAssociatedTokenIfNeeded<'info> {
             init_if_needed,
             payer = payer,
             associated_token::mint = mint,
    -        associated_token::authority = authority,
    +        associated_token::authority = authority
         )]
         pub token: Account<'info, TokenAccount>,
         pub mint: Account<'info, Mint>,
    diff --git a/tests/misc/tests/misc.js b/tests/misc/tests/misc.js
    index fc1b7983d6..3e6cd982f4 100644
    --- a/tests/misc/tests/misc.js
    +++ b/tests/misc/tests/misc.js
    @@ -1002,7 +1002,8 @@ describe("misc", () => {
     
       it("init_if_needed throws if account exists but is not the expected space", async () => {
         const newAcc = anchor.web3.Keypair.generate();
    -    await program.rpc.initWithSpace(3, {
    +    const _irrelevantForTest = 3;
    +    await program.rpc.initWithSpace(_irrelevantForTest, {
           accounts: {
             data: newAcc.publicKey,
             systemProgram: anchor.web3.SystemProgram.programId,
    @@ -1012,7 +1013,7 @@ describe("misc", () => {
         });
     
         try {
    -      await program.rpc.testInitIfNeeded(3, {
    +      await program.rpc.testInitIfNeeded(_irrelevantForTest, {
             accounts: {
               data: newAcc.publicKey,
               systemProgram: anchor.web3.SystemProgram.programId,
    diff --git a/tests/zero-copy/programs/zero-copy/src/lib.rs b/tests/zero-copy/programs/zero-copy/src/lib.rs
    index 58b1beb68a..c6076ea9ff 100644
    --- a/tests/zero-copy/programs/zero-copy/src/lib.rs
    +++ b/tests/zero-copy/programs/zero-copy/src/lib.rs
    @@ -97,7 +97,8 @@ pub struct CreateBar<'info> {
             init,
             seeds = [authority.key().as_ref(), foo.key().as_ref()],
             bump,
    -        payer = authority, owner = *program_id
    +        payer = authority, owner = *program_id,
    +        space = Bar::LEN + 8
         )]
         bar: AccountLoader<'info, Bar>,
         #[account(mut)]
    @@ -132,8 +133,8 @@ pub struct UpdateLargeAccount<'info> {
     }
     
     #[account(zero_copy)]
    -#[derive(Default)]
     #[repr(packed)]
    +#[derive(Default)]
     pub struct Foo {
         pub authority: Pubkey,
         pub data: u64,
    @@ -143,10 +144,13 @@ pub struct Foo {
     }
     
     #[account(zero_copy)]
    -#[derive(Default)]
     pub struct Bar {
    -    pub authority: Pubkey,
    -    pub data: u64,
    +    pub authority: Pubkey, // 32
    +    pub data: u64,         // 8
    +}
    +
    +impl Bar {
    +    pub const LEN: usize = 32 + 8;
     }
     
     #[account(zero_copy)]