Search code examples
rustsolana

Getting unexpected lifetime issue when passing newly constructed array to function


I've been working on a program intended to run on the Solana runtime. I've recently run into a problem where the second item in the array being passed into 'test2' gets some sort of lifetime error. This error goes away when explicit lifetime annotations are added to test1 but I can't figure out why it shows up in the first place.

pub fn test1(
    test_account_1: &AccountInfo,
    test_account_2: &AccountInfo,
    mint_account: &AccountInfo,
) -> ProgramResult {
    test2(&[test_account_1.clone(), test_account_2.clone()]);
    return Ok(());
}

pub fn test2(arr: &[AccountInfo]) {
    for a in arr.iter() {
        println!("{}", a.key)
    }
}

The error:

lifetime mismatch

...but data from test_account_1 flows into test_account_2 here rustc (E0623)

lib.rs(207, 22): these two types are declared with different lifetimes...

lib.rs(208, 22):

lib.rs(211, 37): ...but data from test_account_1 flows into test_account_2 here

Definition of AccountInfo:

/// Account information
#[derive(Clone)]
pub struct AccountInfo<'a> {
    /// Public key of the account
    pub key: &'a Pubkey,
    /// Was the transaction signed by this account's public key?
    pub is_signer: bool,
    /// Is the account writable?
    pub is_writable: bool,
    /// The lamports in the account.  Modifiable by programs.
    pub lamports: Rc<RefCell<&'a mut u64>>,
    /// The data held in this account.  Modifiable by programs.
    pub data: Rc<RefCell<&'a mut [u8]>>,
    /// Program that owns this account
    pub owner: &'a Pubkey,
    /// This account's data contains a loaded program (and is now read-only)
    pub executable: bool,
    /// The epoch at which this account will next owe rent
    pub rent_epoch: Epoch,
}

Solution

  • In order for your array to hold a reference to those AccountsInfo, they need to live for at least the same lifetime. Since they have internal bounds, those need to match too:

    pub fn test1<'a>(
        test_account_1: &AccountInfo<'a>,
        test_account_2: &AccountInfo<'a>,
        mint_account: &AccountInfo,
    ) -> Result<(), ()> {
        test2(&[test_account_1.clone(), test_account_2.clone()]);
        Ok(())
    }
    

    Playground

    Also, depending on your actual needs, you may not need the clone at all:

    pub fn test1<'a>(
        test_account_1: &AccountInfo<'a>,
        test_account_2: &AccountInfo<'a>,
        mint_account: &AccountInfo,
    ) -> Result<(), ()> {
        test2(&[test_account_1, test_account_2]);
        Ok(())
    }
    
    pub fn test2(arr: &[&AccountInfo]) {
        for a in arr.iter() {
            println!("{}", a.key)
        }
    }
    

    Playground