coral-xyz / anchor

⚓ Solana Sealevel Framework
https://anchor-lang.com
Apache License 2.0
3.61k stars 1.32k forks source link

lang: add better error for `deriveAccounts` if space field is missing or cannot be calculated when using`init` #1178

Closed paul-schaaf closed 2 years ago

paul-schaaf commented 2 years ago
#[account]
pub struct User {
    age: u64,
    data: u8
}

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

This code errors with

no function or associated item named `default` found for struct `User` in the current scope
items from traits can only be used if the trait is implemented and in scope
the following trait defines an item `default`, perhaps you need to implement it:
candidate #1: `Default`

because the space constraint is not given which means that anchor will try to use the default trait to infer it.

The error should be sth like:

"space" constraint not provided for "my_account".
Either add it (space = <num_bytes>) or derive/implement "Default" for "User"
so anchor can infer it.
paul-schaaf commented 2 years ago

Im not sure this is possible with the current anchor architecture though. User is not part of the Accounts struct so derive(Accounts) cannot check whether Default is implemented for it.

armaniferrante commented 2 years ago

The #[account] macro should calculate the size at compile time in the same way the ts client does--and use that calculation to implement some type of size/space trait, which can be used instead of Default.

paul-schaaf commented 2 years ago

ok so how about we have the account macro traverse the fields of the data structure and e.g. generates an

impl MyAccount {
    const BORSH_MAXIMUM_SIZE: usize = #size;
}

this would fail if there is a type with a dynamic size (vec, string, etc.). Then you would have to do

#[account(size = 1337)]
pub struct MyAccount {...}

which then results in

impl MyAccount {
    const BORSH_MAXIMUM_SIZE: usize = 1337;
}

one problem that arises with this approach is that space is now connected to MyAccount. So your accounts of the same type all have the same size. probably in most cases this is fine but we could still keep the space constraint in init that would allow an override of BORSH_MAXIMUM_SIZE

paul-schaaf commented 2 years ago

calculation using Default is no longer supported so this is obsolete