当前位置: 首页 > 工具软件 > Solana > 使用案例 >

161-Solana公共账户变量

西门梓
2023-12-01

现在我们要讨论一个问题

现在我们需要有一个合约持有的账户和变量

比如合约持有了一个账户,

这个账户里有一个变量count

每当一个用户调用了某个指令

这个count就+1

但是用户当然是没有权限去主动修改这个变量的

只有调用了某个指令

在指令中,这个count会+1

我们来写一点代码试试看

use borsh::BorshSerialize;
use solana_program::{account_info::{AccountInfo, next_account_info}, entrypoint::ProgramResult, msg, pubkey::Pubkey};
use solana_program::program::invoke;
use spl_associated_token_account::instruction::create_associated_token_account;
use spl_token::instruction::transfer;

use crate::state::{Count, MAX_COUNT_LENGTH};
use crate::utils::{assert_derivation, create_or_allocate_account_raw};

pub fn process_transfer(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
) -> ProgramResult {
    let account_info_iter = &mut accounts.iter();
    let signer_info = next_account_info(account_info_iter)?;
    let signer_ata_info = next_account_info(account_info_iter)?;
    let target_info = next_account_info(account_info_iter)?;
    let target_ata_info = next_account_info(account_info_iter)?;
    let token_mint_info = next_account_info(account_info_iter)?;
    let system_info = next_account_info(account_info_iter)?;
    let token_program_info = next_account_info(account_info_iter)?;
    let ass_program_info = next_account_info(account_info_iter)?;

    let count_info = next_account_info(account_info_iter)?;
    let rent_info = next_account_info(account_info_iter)?;

    if target_ata_info.lamports() <= 0 {
        msg!("Create Associated Token Account");
        invoke(
            &create_associated_token_account(
                signer_info.key,
                target_info.key,
                token_mint_info.key,
            ),
            &[
                signer_info.clone(),
                target_ata_info.clone(),
                target_info.clone(),
                token_mint_info.clone(),
                system_info.clone(),
                token_program_info.clone(),
                ass_program_info.clone(),
            ],
        )?;
    }

    msg!("Transfer Token");
    invoke(
        &transfer(
            token_program_info.key,
            signer_ata_info.key,
            target_ata_info.key,
            signer_info.key,
            &[signer_info.key],
            1,
        )?,
        &[
            signer_ata_info.clone(),
            target_ata_info.clone(),
            signer_info.clone(),
            token_program_info.clone()
        ],
    )?;

    msg!("Create Count Account");
    if count_info.lamports() <= 0 {
        let bump_seed = assert_derivation(
            program_id,
            count_info,
            &[
                "seed_count".as_bytes(),
                program_id.as_ref(),
            ],
        )?;
        let count_seeds = &[
            "seed_count".as_bytes(),
            program_id.as_ref(),
            &[bump_seed],
        ];
        create_or_allocate_account_raw(
            *program_id,
            count_info,
            rent_info,
            system_info,
            signer_info,
            MAX_COUNT_LENGTH,
            count_seeds,
        )?;
    };

    msg!("Update Count");
    let mut count = Count::from_account_info(count_info)?;
    count.count += 1;
    count.serialize(&mut *count_info.try_borrow_mut_data()?)?;

    Ok(())
}

使用2个账号分别都成功了

其实这里的关键点就在于

这个pda账号的拥有者是谁

我们来看看创建账户时的信息

#[inline(always)]
pub fn create_or_allocate_account_raw<'a>(
    program_id: Pubkey,
    new_account_info: &AccountInfo<'a>,
    rent_sysvar_info: &AccountInfo<'a>,
    system_program_info: &AccountInfo<'a>,
    payer_info: &AccountInfo<'a>,
    size: usize,
    signer_seeds: &[&[u8]],
) -> Result<(), ProgramError> {
    let rent = &Rent::from_account_info(rent_sysvar_info)?;
    let required_lamports = rent
        .minimum_balance(size)
        .max(1)
        .saturating_sub(new_account_info.lamports());

    if required_lamports > 0 {
        msg!("Transfer {} lamports to the new account", required_lamports);
        invoke(
            &system_instruction::transfer(&payer_info.key, new_account_info.key, required_lamports),
            &[
                payer_info.clone(),
                new_account_info.clone(),
                system_program_info.clone(),
            ],
        )?;
    }

    msg!("Allocate space for the account");
    invoke_signed(
        &system_instruction::allocate(new_account_info.key, size.try_into().unwrap()),
        &[new_account_info.clone(), system_program_info.clone()],
        &[&signer_seeds],
    )?;

    msg!("Assign the account to the owning program");
    invoke_signed(
        &system_instruction::assign(new_account_info.key, &program_id),
        &[new_account_info.clone(), system_program_info.clone()],
        &[&signer_seeds],
    )?;
    msg!("Completed assignation!");

    Ok(())
}

注意看这一段代码

    msg!("Assign the account to the owning program");
    invoke_signed(
        &system_instruction::assign(new_account_info.key, &program_id),
        &[new_account_info.clone(), system_program_info.clone()],
        &[&signer_seeds],
    )?;

当assign的时候

pub fn assign(pubkey: &Pubkey, owner: &Pubkey) -> Instruction {
    let account_metas = vec![AccountMeta::new(*pubkey, true)];
    Instruction::new_with_bincode(
        system_program::id(),
        &SystemInstruction::Assign { owner: *owner },
        account_metas,
    )
}

第一个是账户

第二个是owner

所以最重要的就是要决定好owner

 类似资料: