Cross-program invocation with unauthorized signer or writable account

Viewed 2525

I am trying to create a transaction on python for the program that I wrote, and I am falling into an issue that I can't really pinpoint how to solve it.

program_id = PublicKey("9qm7AEJFHQ8SqJrmfofWK6maWRwKvQwK8uy8w3PVZLQw")
program_id_account_meta = AccountMeta(program_id, False, False)
payer_account_meta = AccountMeta(payer_keypair.public_key, True, False)
vault_account_meta = AccountMeta(PublicKey("G473EkeR5gowVn8CRwTSDop3zPwaNixwp62qi7nyVf4z"), False, False)

accounts = [
    program_id_account_meta,
    payer_account_meta, 
    vault_account_meta]


transaction = Transaction()
transaction.add(TransactionInstruction(
    accounts,
    program_id,
    bytes([0])
))

client.send_transaction(transaction, payer_keypair)

When I execute it, I get the error whose image is attached. I did play with setting the payer_account_meta's writable value to True, and no luck.enter image description here

I am attaching my solana program's code here, just incase that could be the source of the error, although it seems the error occurs before my program is being even sent the transaction for execution.


entrypoint!(process_instructions);
pub enum Instructions{
    CreateAccount {
    },
}

impl Instructions{
    fn unpackinst(input: &[u8]) -> Result<Self, ProgramError>{
        let (&instr, _) = input.split_first().ok_or(ProgramError::InvalidArgument)?;
        Ok(match instr{
            0 => {

                Self::CreateAccount{
                }
    
            }

            _ => return Err(ProgramError::InvalidInstructionData.into())
        })
    }
}


pub fn process_instructions(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8])-> ProgramResult{
    let instruction = Instructions::unpackinst(instruction_data)?;

    let account_info_iter =  &mut accounts.iter();

    match instruction {
        Instructions::CreateAccount{
        } => {
            let payer_account_info = next_account_info(account_info_iter)?;
            let vault = next_account_info(account_info_iter)?;
            let temp_key = Pubkey::from_str("G473EkeR5gowVn8CRwTSDop3zPwaNixwp62qi7nyVf4z").unwrap();
            if vault.key != &temp_key && program_id != program_id {
                Err(ProgramError::InvalidAccountData)?
            }
            let price: u64 = (0.5 * (i32::pow(10,9)) as f64) as u64;
            invoke(
                &system_instruction::transfer(
                    &payer_account_info.key,
                    &temp_key,
                    price,
                ),
                &[
                    payer_account_info.clone(),
                    vault.clone()
                ]
            )?;}} Ok(())}


1 Answers

You're attempting to transfer between accounts that aren't declared as writable, so the runtime is correctly saying that there has been privilege escalation during your invocation of system_instruction::transfer.

Try changing your Python AccountMeta declarations to:

payer_account_meta = AccountMeta(payer_keypair.public_key, True, True)
vault_account_meta = AccountMeta(PublicKey("G473EkeR5gowVn8CRwTSDop3zPwaNixwp62qi7nyVf4z"), False, True)

More info at https://docs.solana.com/developing/programming-model/runtime#policy, specifically:

Only the owner may change account data.
    And if the account is writable.

Here, the owner is the system program during transfer, so it can only change the amounts if the accounts are writable.

Also, you need to pass in the system program in order to invoke it during your program, and not pass in your own program. So you'll want to do instead:

from solana.system_program import SYS_PROGRAM_ID
program_id_account_meta = AccountMeta(SYS_PROGRAM_ID, False, False)

and add it last in your list of accounts, which becomes

accounts = [
    payer_account_meta, 
    vault_account_meta,
    program_id_account_meta,
]
Related