I am writing a Solana smart contract that integrates with Mango Markets, and am having an error that I am struggling to nail down. Here is the offending code:
let mango_acc_info_clone = &ctx.accounts.mango_account.clone();
let res = MangoAccount::load_mut_checked(
mango_acc_info_clone,
&ctx.accounts.mango_program_id.key().clone(),
&ctx.accounts.mango_group.key().clone(),
);
let mango_account = match res {
Ok(acc) => acc,
Err(error) => panic!("failed to place perp order: {:?}", error),
};
let accounts = [
ctx.accounts.mango_program_id.clone(),
ctx.accounts.mango_group.clone(),
ctx.accounts.mango_account.clone(),
ctx.accounts.mango_account_owner.clone(),
ctx.accounts.mango_cache.clone(),
ctx.accounts.mango_perp_market.clone(),
ctx.accounts.mango_bids.clone(),
ctx.accounts.mango_asks.clone(),
ctx.accounts.mango_event_queue.clone(),
];
let result = mango::instruction::place_perp_order(
&ctx.accounts.mango_program_id.key().clone(),
&ctx.accounts.mango_group.key().clone(),
&ctx.accounts.mango_account.key().clone(),
&ctx.accounts.mango_account_owner.key().clone(),
&ctx.accounts.mango_cache.key().clone(),
&ctx.accounts.mango_perp_market.key().clone(),
&ctx.accounts.mango_bids.key().clone(),
&ctx.accounts.mango_asks.key().clone(),
&ctx.accounts.mango_event_queue.key().clone(),
None,
&mango_account.spot_open_orders,
converted_side,
price,
quantity,
client_order_id,
converted_order_type,
reduce_only,
);
let is = match result {
Ok(is) => is,
Err(error) => panic!("failed to place order: {:?}", error),
};
invoke_signed(
&is,
&accounts,
&[&[
MANGO_OWNER_PDA_SEED,
ctx.accounts.vault.name.as_ref(),
&[_mango_owner_bump],
]],
)
I believe the error to be with the load_mut_checked
function, which is returning a RefMut<MangoAccount>
type. Here is the error:
solana.rpc.core.RPCException: {'code': -32002, 'message': 'Transaction simulation failed: Error processing Instruction 0: instruction tries to borrow reference for an account which is already borrowed', 'data': {'accounts': None, 'err': {'InstructionError': [0, 'AccountBorrowFailed']}, 'logs': ['Program AQPDVpAsDtd8cfXVjrUEKrhchF4cYwST2wyq3tJa82ci invoke [1]', 'Program log: Debugging', 'Program log: 3', 'Program log: Failed to borrow a reference to account data, already borrowed', 'Program AQPDVpAsDtd8cfXVjrUEKrhchF4cYwST2wyq3tJa82ci consumed 13081 of 200000 compute units', 'Program AQPDVpAsDtd8cfXVjrUEKrhchF4cYwST2wyq3tJa82ci failed: instruction tries to borrow reference for an account which is already borrowed'], 'unitsConsumed': 0}}
I have tried calling .to_owned()
on the account, but that just gives me a different error:
solana.rpc.core.RPCException: {'code': -32002, 'message': 'Transaction simulation failed: Error processing Instruction 0: Program failed to complete', 'data': {'accounts': None, 'err': {'InstructionError': [0, 'ProgramFailedToComplete']}, 'logs': ['Program AQPDVpAsDtd8cfXVjrUEKrhchF4cYwST2wyq3tJa82ci invoke [1]', 'Program AQPDVpAsDtd8cfXVjrUEKrhchF4cYwST2wyq3tJa82ci consumed 5013 of 200000 compute units', 'Program failed to complete: Access violation in stack frame 7 at address 0x200007ae0 of size 8 by instruction #52535', 'Program AQPDVpAsDtd8cfXVjrUEKrhchF4cYwST2wyq3tJa82ci failed: Program failed to complete'], 'unitsConsumed': 0}}
Any help would be great. I am very new to Rust and Solana programming so let me know if any additional information can help. I am running this on a local validator.
I believe the error comes from trying to mutably borrow and immutably borrow at the same time, which is not allowed for
RefCell
: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrowSince the cross-program invocation at
invoke_signed
may need to mutably borrow data, the easiest way to fix this is to:MangoAccount::load_checked
if it existsinvoke_signed
, usingdrop(mango_account)
once you're done with it