本教程将展示如何在 Solana Anchor 中用不同签名者(Signer)初始化和更新账户,并探讨权限控制机制。
此前文章中,我们仅使用单一签名者初始化并修改账户,功能受限。现实场景中,如 Alice 向 Bob 转移积分,需允许 Alice 修改 Bob 创建的账户。本教程将展示如何在 Solana Anchor 中用不同签名者(Signer)初始化和更新账户,并探讨权限控制机制。
初始化账户的 Rust 代码保持不变,使用标准 Anchor 模式创建账户。
use anchor_lang::prelude::*;
use std::mem::size_of;
declare_id!("26Kiu5LSV5xXDN3yGwE8L6aU59kKRKdyyKtSQv5Vu5VC");
#[program]
pub mod other_write {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        Ok(())
    }
}
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init,
              payer = signer,
              space=size_of::<MyStorage>() + 8,
              seeds = [],
              bump)]
    pub my_storage: Account<'info, MyStorage>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}
#[account]
pub struct MyStorage {
    x: u64,
}客户端调整
测试代码引入新签名者,需显式指定:
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { OtherWrite } from "../target/types/other_write";
// this airdrops sol to an address
async function airdropSol(publicKey, amount) {
  let airdropTx = await anchor.getProvider().connection.requestAirdrop(publicKey, amount);
  await confirmTransaction(airdropTx);
}
async function confirmTransaction(tx) {
  const latestBlockHash = await anchor.getProvider().connection.getLatestBlockhash();
  await anchor.getProvider().connection.confirmTransaction({
    blockhash: latestBlockHash.blockhash,
    lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
    signature: tx,
  });
}
describe("other_write", () => {
  anchor.setProvider(anchor.AnchorProvider.env());
  const program = anchor.workspace.OtherWrite as Program<OtherWrite>;
  it("Is initialized!", async () => {
    const newKeypair = anchor.web3.Keypair.generate();
    await airdropSol(newKeypair.publicKey, 1e9); // 1 SOL
    let seeds = [];
    const [myStorage, _bump] = anchor.web3.PublicKey.findProgramAddressSync(seeds, program.programId);
    await program.methods.initialize().accounts({
      myStorage: myStorage,
      signer: newKeypair.publicKey // ** THIS MUST BE EXPLICITLY SPECIFIED **
    }).signers([newKeypair]).rpc();
  });
});为何两次指定签名者?
字段名可自定义(如 fren 替代 signer),只需 Rust 与客户端一致。
Signer<'info> 表示交易签名者,Anchor 自动验证其公钥与签名一致。若使用非默认签名者,需显式传递公钥,否则 Anchor 默认使用环境签名者(provider wallet)。
若签名与公钥不匹配,会触发错误:
以下程序展示 Alice 初始化账户,Bob 更新其值。
use anchor_lang::prelude::*;
use std::mem::size_of;
declare_id!("26Kiu5LSV5xXDN3yGwE8L6aU59kKRKdyyKtSQv5Vu5VC");
#[program]
pub mod other_write {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        Ok(())
    }
    pub fn update_value(ctx: Context<UpdateValue>, new_value: u64) -> Result<()> {
        ctx.accounts.my_storage.x = new_value;
        Ok(())
    }
}
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init,
              payer = fren,
              space=size_of::<MyStorage>() + 8,
              seeds = [],
              bump)]
    pub my_storage: Account<'info, MyStorage>,
    #[account(mut)]
    pub fren: Signer<'info>, // A public key is passed here
    pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct UpdateValue<'info> {
    #[account(mut, seeds = [], bump)]
    pub my_storage: Account<'info, MyStorage>,
      // THIS FIELD MUST BE INCLUDED
    #[account(mut)]
    pub fren: Signer<'info>,
}
#[account]
pub struct MyStorage {
    x: u64,
}
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { OtherWrite } from "../target/types/other_write";
// this airdrops sol to an address
async function airdropSol(publicKey, amount) {
  let airdropTx = await anchor.getProvider().connection.requestAirdrop(publicKey, amount);
  await confirmTransaction(airdropTx);
}
async function confirmTransaction(tx) {
  const latestBlockHash = await anchor.getProvider().connection.getLatestBlockhash();
  await anchor.getProvider().connection.confirmTransaction({
    blockhash: latestBlockHash.blockhash,
    lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
    signature: tx,
  });
}
describe("other_write", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());
  const program = anchor.workspace.OtherWrite as Program<OtherWrite>;
  it("Is initialized!", async () => {
    const alice = anchor.web3.Keypair.generate();
    const bob = anchor.web3.Keypair.generate();
    const airdrop_alice_tx = await anchor.getProvider().connection.requestAirdrop(alice.publicKey, 1 * anchor.web3.LAMPORTS_PER_SOL);
    await confirmTransaction(airdrop_alice_tx);
    const airdrop_alice_bob = await anchor.getProvider().connection.requestAirdrop(bob.publicKey, 1 * anchor.web3.LAMPOINTS_PER_SOL);
    await confirmTransaction(airdrop_alice_bob);... 
                如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!