现在我们要讨论一个问题
现在我们需要有一个合约持有的账户和变量
比如合约持有了一个账户,
这个账户里有一个变量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