本教程将展示如何在 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);...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!