0

I am creating simple contract for storing ipfs hashes (see in attachment). When trying to call instruction 1 (AddIpfsHash) from python via solana-py and solders I get following error:

"Transaction simulation failed: Error processing Instruction 0: Failed to serialize or deserialize account data: Unknown"

I have tried multiple things, but i am not quite sure how to go on (i am not Rust developer, this is just for my Master Thesis :D) . If you could provide any help I would be very greatful ! If you'd like to see the code from python I will be happy to share and check it with you.

use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    pubkey::Pubkey,
    program_error::ProgramError,
    rent::Rent,
    sysvar::Sysvar,
    msg
};

// Define the instruction types this program can handle
pub enum Instruction {
    InitializeAccount,
    AddIpfsHash { hash: String },
}

// Struct to represent the IPFS record
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct IpfsRecord {
    pub ipfs_hashes: Vec<String>,
}

// Deserialize instruction data into the Instruction enum
impl Instruction {
    pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
        let (&instruction_type, rest) = input.split_first().ok_or(ProgramError::InvalidInstructionData)?;

        Ok(match instruction_type {
            0 => Self::InitializeAccount,
            1 => {
                let hash = String::from_utf8(rest.to_vec()).map_err(|_| ProgramError::InvalidInstructionData)?;
                Self::AddIpfsHash { hash }
            },
            _ => return Err(ProgramError::InvalidInstructionData),
        })
    }
}

// Entry point of the program
entrypoint!(process_instruction);

// Program entry function
fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    let accounts_iter = &mut accounts.iter();
    let account = next_account_info(accounts_iter)?;

    if account.owner != program_id {
        msg!("Account does not have the correct program id");
        return Err(ProgramError::IncorrectProgramId);
    }

    let instruction = Instruction::unpack(instruction_data)?;

    match instruction {
        Instruction::InitializeAccount => {
            let rent_exemption = Rent::get()?.minimum_balance(account.data_len());
            if **account.lamports.borrow() < rent_exemption {
                return Err(ProgramError::InsufficientFunds);
            }

            let ipfs_record = IpfsRecord { ipfs_hashes: Vec::new() };
            ipfs_record.serialize(&mut &mut account.data.borrow_mut()[..])?;
        },
        Instruction::AddIpfsHash { hash } => {
            let mut ipfs_record = IpfsRecord::try_from_slice(&account.data.borrow())?;
            ipfs_record.ipfs_hashes.push(hash);
            msg!("Zde");
            ipfs_record.serialize(&mut &mut account.data.borrow_mut()[..])?;
        },
    }

    Ok(())
}

1 Answer 1

0

The error is most likely getting triggered on this line:

let mut ipfs_record = IpfsRecord::try_from_slice(&account.data.borrow())?;

Be sure that you've allocated enough space in the account to accommodate many strings using system_instruction::create_account first.

You may also be tripping up a length check on the normal try_from_slice if the account has a lot of bytes allocated, so you may need to use the try_from_slice_unchecked helper at https://github.com/anza-xyz/agave/blob/aba8ce5f3ef5af4c7241906ccf419e0dd4d7ff69/sdk/program/src/borsh.rs#L195

1
  • Thanks that try_from_slice_unchecked helped! Commented Mar 23 at 11:04

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.