I am facing an issue when using solana-sdk to call a function on my Solana program.
I have the following Program, made using Anchor:
#[program]
pub mod myprogram {
// does not write on the SomeAccount account
pub fn do_smth(
ctx: Context<DoSmth>,
data: Vec<u8>,
signatures: Vec<Vec<u8>>,
) -> Result<()> {
....
}
}
#[derive(Accounts)]
pub struct DoSmth<'info> {
// #[account(mut)]
pub some_accounts: Account<'info, SomeAccounts>,
}
#[account]
pub struct SomeAccounts{
pub some_accounts: Vec<Vec<u8>>, // 4 + (64 bytes per public key * 20 public keys) = 1284 bytes
}
I can successfully call my "initialize" function that set the SomeAccounts
account.
Then, in another Rust crate, I'm doing this in order to build the payload:
#[derive(BorshSerialize, BorshDeserialize)]
struct DoSmth{
data: Vec<u8>,
signatures: Vec<Vec<u8>>,
}
fn build_payload(
data: Vec<u8>,
some_other_accounts: Vec<Pubkey>,
program_id: &Pubkey,
signatures: Vec<Signature>,
signer: &Pubkey,
) -> Result<Instruction> {
let some_accounts_pubkey: [u8; 32] = bs58::decode(SOME_ACCOUNT_ADDRESS)
.into_vec()?
.try_into()
.expect("44 caracters long base58 string should be 32 bytes long.");
let some_accounts_account: AccountMeta = AccountMeta {
pubkey: Pubkey::from(some_accounts_pubkey),
is_signer: false,
is_writable: false,
};
let mut data = vec![0, inner_data.len() as u8];
data.extend_from_slice(&inner_data);
data.push(signatures.len() as u8);
for sig in signatures {
data.extend_from_slice(&sig);
}
let do_smth = DoSmth {
data,
signatures: signatures.map(|s| s.to_bytes()).collect()
};
let instruction = Instruction::new_with_borsh(*program_id, &data, vec![some_other_accounts, AccountMeta::new(*signer, true)]);
Ok(instruction)
// Also, I tried this:
// let mut i_data = vec![0, data.len() as u8];
// i_data.extend_from_slice(&data);
// i_data.push(signatures.len() as u8);
// for sig in signatures {
// i_data.extend_from_slice(&sig);
// }
// let instruction = Instruction {
// program_id: *program_id,
// accounts: vec![some_other_accounts, AccountMeta::new(*signer, true)],
// i_data
// };
// Ok(instruction)
}
Then, I sign and execute the payload this way:
let mut transaction = Transaction::new_with_payer(&[payload], Some(&keypair.pubkey()));
let block_hash = rpc_client.get_latest_blockhash().await.unwrap();
transaction.try_sign(&[&keypair], block_hash).unwrap();
let signature = rpc_client.send_and_confirm_transaction_with_spinner(&transaction).await.unwrap();
Now, when executing this, I encounter the following error:
1: Program ... invoke [1]
2: Program log: AnchorError occurred. Error code: InstructionFallbackNotFound. Error Number; 101. Error Message: Fallback functions are not supported.
From what I've read, it mean the instruction didn't match my do_smth
, so it tried to find a fallback function that I did not do. I don't understand what I am missing for my payload to match the right instruction. I verified that the public keys are valid, I verified that my signer account is funded, so i believe the issue lies in my code that uses solana_sdk, but I cannot find the actual issue