Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to borrow a reference to account data, already borrowed #2

Open
PhongVu07 opened this issue Jul 17, 2022 · 5 comments
Open

Failed to borrow a reference to account data, already borrowed #2

PhongVu07 opened this issue Jul 17, 2022 · 5 comments

Comments

@PhongVu07
Copy link

I'm having this issue when calling close_raffle method:

    Program CQvpjShzASLhc3cy1S2h8J777R9St564JBXEvnM1AcvJ invoke [1]
    Program log: Instruction: CloseRaffle
    Program log: ProgramError occurred. Error Code: AccountBorrowFailed. Error Number: 51539607552. Error Message: Failed to borrow a reference to account data, already borrowed.
    Program CQvpjShzASLhc3cy1S2h8J777R9St564JBXEvnM1AcvJ consumed 42212 of 200000 compute units
    Program CQvpjShzASLhc3cy1S2h8J777R9St564JBXEvnM1AcvJ failed: instruction tries to borrow reference for an account which is already borrowed```

Any idea?
@Flawm
Copy link
Owner

Flawm commented Jul 17, 2022

definitely odd, on review I think it's because I copy/pasted some code and didn't clean it up so to speak.

I believe commit de7bb09 fixes this, if you want to upload some message bodies I can repro and confirm, or you could try to use program RafXcAJfB3wVzyH7cHuDqyVjYeQ4Qy8RjQEbCPvttK9

I deployed this change to devnet and mainnet just now.

@PhongVu07
Copy link
Author

Still dose not work @Flawm ,

I think it was because ticket_data and fixed_raffle_lams both borrow from fixed ticket account per this doc. How do you think?

@PhongVu07
Copy link
Author

Full message:

Transaction simulation failed: Error processing Instruction 0: Program failed to complete 
    Program CQvpjShzASLhc3cy1S2h8J777R9St564JBXEvnM1AcvJ invoke [1]
    Program log: Instruction: CloseRaffle
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
    Program log: Instruction: Transfer
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3052 of 159224 compute units
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
    Program log: Instruction: Transfer
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3132 of 153362 compute units
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
    Program log: Instruction: CloseAccount
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2104 of 147439 compute units
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
    Program log: Instruction: CloseAccount
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2104 of 142541 compute units
    Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
    Program log: panicked at 'already borrowed: BorrowMutError', programs/raffle/src/lib.rs:183:59
    Program CQvpjShzASLhc3cy1S2h8J777R9St564JBXEvnM1AcvJ consumed 61920 of 200000 compute units
    Program failed to complete: BPF program panicked
    Program CQvpjShzASLhc3cy1S2h8J777R9St564JBXEvnM1AcvJ failed: Program failed to complete

@Flawm
Copy link
Owner

Flawm commented Jul 19, 2022

can you upload the client side transaction that is calling the closeRaffle method? It might be a bug there 👀

@PhongVu07
Copy link
Author

This is my request:

curl 'https://api.devnet.solana.com/' \
  -H 'authority: api.devnet.solana.com' \
  -H 'accept: */*' \
  -H 'accept-language: en-US,en;q=0.9' \
  -H 'content-type: application/json' \
  -H 'origin: http://localhost:3000' \
  -H 'referer: http://localhost:3000/' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: cross-site' \
  -H 'sec-gpc: 1' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36' \
  --data-raw '{"method":"sendTransaction","jsonrpc":"2.0","params":["AYSsMlK7eEtUW8HHYxerHUE9v3U/99rzC4dlWshgRqcCsYt/iuxIWlIX3Q0zWwSgleA19y69zMkORD3RUkoa5AwBAAQMfLcbnOylxDZhyAcCVDzchvYWwhhUbymXhbAJkYkp5AgXnJB9FpItZaqgLBIFQLQVRRxxVvUvg8fiLHLYvwQM5R6zU5pc2qXkTttn1+A8VU6oE3IOlwd4oscW6QWpBy0hLUOJnVkExf1mWFB9ktZREdT+RPZQnLnZVh1gZZfIIUI8ERI2AmUc1zS32EPhqrJhg2Bv0BLlRyKSEae8Y8lhOUfc8yeOtPdXct1MjtIn3VAfcFVVFSkQOfywvc845GxP+rebGFJHoIex9mrZo/OorrBWyOrmHlIBraWel8358poFVIpg4m912awWZ7NHxVJ7eRvGut8E3O1yj5pMiil2MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMJI68C6MWCe32RVwdgsvm13nBko9nrrH9a+OcIBN7upkcXKIAXEdwhA3VKGLc0xSN0E5q8spOczEycCjZIypwbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpnuCtR5AqjIiDj6iYZj5GBNEWBGFhlu49kg0W0dRJ3mwBCgwABQECCQYGCAsDBAcJ3IGAM0ZC0XwA",{"encoding":"base64","preflightCommitment":"processed"}],"id":"5c287d3e-bc96-4da9-87de-8421e92443b8"}' \
  --compressed

This is my deployed program, but it is basically a fork with property name changed. The function code is:

pub fn close_raffle(ctx: Context<CloseRaffle>, force_close: bool) -> Result<()> {
        let is_admin = ctx.accounts.payer.key.to_string() == MOON_KEY && force_close;
        let ticket_account = &ctx.accounts.fixed_raffle.to_account_info();
        let ticket_data = &ticket_account.data.borrow();

        if ctx.accounts.fixed_raffle.owner != &ID
            || &ticket_data[8..40] != ctx.accounts.raffle.id.as_ref()
        {
            return err!(CustomError::InputError);
        }

        if force_close && !is_admin {
            return err!(CustomError::InputError);
        }

        let raffle = &ctx.accounts.raffle;

        if raffle.sent_out == 0 && raffle.tickets_purchased > 0 && !is_admin {
            return err!(CustomError::RaffleStarted);
        }

        // they need to pay out all winners
        if raffle.winners.len() != 0 && !is_admin {
            return err!(CustomError::CantScam);
        }

        let seeds: &[&[_]] = &[&[
            ctx.accounts.raffle.owner.as_ref(),
            ctx.accounts.ticket_mint.to_account_info().key.as_ref(),
            ctx.accounts.prize_mint.to_account_info().key.as_ref(),
            &[raffle.bump],
        ]];

        // take prize tokens back from escrow
        anchor_spl::token::transfer(
            CpiContext::new_with_signer(
                ctx.accounts.token_program.to_account_info(),
                anchor_spl::token::Transfer {
                    from: ctx.accounts.escrow_prize_token_account.to_account_info(),
                    to: ctx.accounts.prize_token_account.to_account_info(),
                    authority: ctx.accounts.raffle.to_account_info(),
                },
                seeds,
            ),
            // draw back the prize tokens if there are any left over
            raffle.prize_quantity - (raffle.per_win * raffle.sent_out as u64),
        )?;

        if raffle.burn && !is_admin {
            // burn
            anchor_spl::token::burn(
                CpiContext::new_with_signer(
                    ctx.accounts.token_program.to_account_info(),
                    anchor_spl::token::Burn {
                        mint: ctx.accounts.ticket_mint.to_account_info(),
                        from: ctx.accounts.escrow_ticket_token_account.to_account_info(),
                        authority: ctx.accounts.raffle.to_account_info(),
                    },
                    seeds,
                ),
                raffle.tickets_purchased,
            )?;
        } else {
            // take paid tokens back from escrow
            anchor_spl::token::transfer(
                CpiContext::new_with_signer(
                    ctx.accounts.token_program.to_account_info(),
                    anchor_spl::token::Transfer {
                        from: ctx.accounts.escrow_ticket_token_account.to_account_info(),
                        to: ctx.accounts.ticket_token_account.to_account_info(),
                        authority: ctx.accounts.raffle.to_account_info(),
                    },
                    seeds,
                ),
                raffle.tickets_purchased * raffle.ticket_price,
            )?;
        }

        anchor_spl::token::close_account(CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            anchor_spl::token::CloseAccount {
                account: ctx.accounts.escrow_ticket_token_account.to_account_info(),
                destination: ctx.accounts.payer.to_account_info(),
                authority: ctx.accounts.raffle.to_account_info(),
            },
            seeds,
        ))?;

        anchor_spl::token::close_account(CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            anchor_spl::token::CloseAccount {
                account: ctx.accounts.escrow_prize_token_account.to_account_info(),
                destination: ctx.accounts.moon.to_account_info(),
                authority: ctx.accounts.raffle.to_account_info(),
            },
            seeds,
        ))?;

        let raffle = &ctx.accounts.raffle.to_account_info();
        let fixed_raffle = &ctx.accounts.fixed_raffle.to_account_info();

        let payer = &ctx.accounts.payer.to_account_info();
        let moon = &ctx.accounts.moon.to_account_info();

        let mut escrow_lams = raffle.lamports.borrow_mut();
        let mut fixed_raffle_lams = fixed_raffle.lamports.borrow_mut();

        if payer.key == moon.key {
            let mut payer_lams = payer.lamports.borrow_mut();
            **payer_lams += **escrow_lams;
            **payer_lams += **fixed_raffle_lams;
        } else {
            let mut moon_lams = moon.lamports.borrow_mut();
            let mut payer_lams = payer.lamports.borrow_mut();

            **moon_lams += **escrow_lams;
            **moon_lams += **fixed_raffle_lams / 10;

            **payer_lams += **fixed_raffle_lams - **fixed_raffle_lams / 10;
        }

        **escrow_lams = 0;
        **fixed_raffle_lams = 0;

        Ok(())
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants